Deprecate FabricEntityTypeBuilder & FabricBlockEntityTypeBuilder in favour of the vanilla classes ()

* Replace FabricEntityTypeBuilder with EntityTypeBuilder + iface injection

* Finish and test entity type builder

* Deprecate FabricBlockEntityTypeBuilder

* Review fix

* Fixes based on review

* Some fixes

* Checkstyle
This commit is contained in:
modmuss 2024-04-10 22:15:13 +01:00 committed by modmuss50
parent d73f365284
commit 44e6689f3c
13 changed files with 674 additions and 59 deletions

View file

@ -4,7 +4,7 @@ plugins {
id "idea"
id "maven-publish"
id 'jacoco'
id "fabric-loom" version "1.6.3" apply false
id "fabric-loom" version "1.6.5" apply false
id "com.diffplug.spotless" version "6.20.0"
id "org.ajoberstar.grgit" version "3.1.0"
id "me.modmuss50.remotesign" version "0.4.0" apply false

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.object.builder.v1.block.entity;
import com.mojang.datafixers.types.Type;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
/**
* General-purpose Fabric-provided extensions for {@link BlockEntityType}.
*/
public interface FabricBlockEntityType {
/**
* General-purpose Fabric-provided extensions for {@link BlockEntityType.Builder}.
*
* <p>Note: This interface is automatically implemented on {@link BlockEntityType.Builder} via Mixin and interface injection.
*/
interface Builder<T extends BlockEntity> {
/**
* Builds the {@link BlockEntityType}, see {@link BlockEntityType.Builder#build(Type)}.
*
* @return the built {@link BlockEntityType}
*/
default BlockEntityType<T> build() {
throw new AssertionError("Implemented in Mixin");
}
}
}

View file

@ -33,7 +33,10 @@ import net.minecraft.util.math.BlockPos;
*
* <p>Alternatively, use the access widener for {@link BlockEntityType.BlockEntityFactory}
* in Fabric Transitive Access Wideners (v1).
*
* @deprecated Use {@link BlockEntityType.Builder} directly.
*/
@Deprecated
public final class FabricBlockEntityTypeBuilder<T extends BlockEntity> {
private final Factory<? extends T> factory;
private final List<Block> blocks;
@ -43,6 +46,10 @@ public final class FabricBlockEntityTypeBuilder<T extends BlockEntity> {
this.blocks = blocks;
}
/**
* @deprecated Use {@link BlockEntityType.Builder#create(BlockEntityType.BlockEntityFactory, Block...)}.
*/
@Deprecated
public static <T extends BlockEntity> FabricBlockEntityTypeBuilder<T> create(Factory<? extends T> factory, Block... blocks) {
List<Block> blocksList = new ArrayList<>(blocks.length);
Collections.addAll(blocksList, blocks);
@ -55,7 +62,9 @@ public final class FabricBlockEntityTypeBuilder<T extends BlockEntity> {
*
* @param block the supported block
* @return this builder
* @deprecated Use {@link BlockEntityType.Builder#create(BlockEntityType.BlockEntityFactory, Block...)}.
*/
@Deprecated
public FabricBlockEntityTypeBuilder<T> addBlock(Block block) {
this.blocks.add(block);
return this;
@ -66,22 +75,36 @@ public final class FabricBlockEntityTypeBuilder<T extends BlockEntity> {
*
* @param blocks the supported blocks
* @return this builder
* @deprecated Use {@link BlockEntityType.Builder#create(BlockEntityType.BlockEntityFactory, Block...)}.
*/
@Deprecated
public FabricBlockEntityTypeBuilder<T> addBlocks(Block... blocks) {
Collections.addAll(this.blocks, blocks);
return this;
}
/**
* @deprecated Use {@link BlockEntityType.Builder#build()}.
*/
@Deprecated
public BlockEntityType<T> build() {
return build(null);
}
/**
* @deprecated Use {@link BlockEntityType.Builder#build(Type)}.
*/
@Deprecated
public BlockEntityType<T> build(Type<?> type) {
return BlockEntityType.Builder.<T>create(factory::create, blocks.toArray(new Block[0]))
.build(type);
}
/**
* @deprecated Use {@link BlockEntityType.BlockEntityFactory}.
*/
@FunctionalInterface
@Deprecated
public interface Factory<T extends BlockEntity> {
T create(BlockPos blockPos, BlockState blockState);
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.object.builder.v1.entity;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.SpawnRestriction;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.world.Heightmap;
import net.fabricmc.fabric.impl.object.builder.FabricEntityTypeImpl;
/**
* General-purpose Fabric-provided extensions for {@link EntityType}.
*/
public interface FabricEntityType {
/**
* General-purpose Fabric-provided extensions for {@link EntityType.Builder}.
*
* <p>Note: This interface is automatically implemented on {@link EntityType.Builder} via Mixin and interface injection.
*/
interface Builder<T extends Entity> {
/**
* Sets whether the entity's velocity should always be updated.
*
* @param alwaysUpdateVelocity whether the entity's velocity should always be updated
* @return this builder
*/
default EntityType.Builder<T> alwaysUpdateVelocity(boolean alwaysUpdateVelocity) {
throw new AssertionError("Implemented in Mixin");
}
/**
* Build the entity type from the builder. Same as {@link EntityType.Builder#build(String)} but without an id.
*
* @return the entity type instance
*/
default EntityType<T> build() {
throw new AssertionError("Implemented in Mixin");
}
/**
* Creates an entity type builder for a living entity.
*
* <p>This entity's spawn group will automatically be set to {@link SpawnGroup#MISC}.
*
* @param <T> the type of entity
* @param livingBuilder a function to configure living entity specific properties
*
* @return a new living entity type builder
*/
static <T extends LivingEntity> EntityType.Builder<T> createLiving(EntityType.EntityFactory<T> factory, SpawnGroup spawnGroup, UnaryOperator<Living<T>> livingBuilder) {
return FabricEntityTypeImpl.Builder.createLiving(factory, spawnGroup, livingBuilder);
}
/**
* Creates an entity type builder for a mob entity.
*
* @param <T> the type of entity
* @param mobBuilder a function to configure mob entity specific properties
*
* @return a new mob entity type builder
*/
static <T extends MobEntity> EntityType.Builder<T> createMob(EntityType.EntityFactory<T> factory, SpawnGroup spawnGroup, UnaryOperator<Mob<T>> mobBuilder) {
return FabricEntityTypeImpl.Builder.createMob(factory, spawnGroup, mobBuilder);
}
/**
* A builder for additional properties of a living entity, use via {@link #createLiving(EntityType.EntityFactory, SpawnGroup, UnaryOperator)}.
* @param <T> the type of living entity
*/
interface Living<T extends LivingEntity> {
/**
* Sets the default attributes for a type of living entity.
*
* @param defaultAttributeBuilder a function to generate the default attribute builder from the entity type
* @return this builder for chaining
*/
Living<T> defaultAttributes(Supplier<DefaultAttributeContainer.Builder> defaultAttributeBuilder);
}
/**
* A builder for additional properties of a mob entity, use via {@link #createMob(EntityType.EntityFactory, SpawnGroup, UnaryOperator)}.
* @param <T> the type of mob entity
*/
interface Mob<T extends MobEntity> extends Living<T> {
/**
* Registers a spawn restriction for this entity.
*
* <p>This is used by mobs to determine whether Minecraft should spawn an entity within a certain context.
*
* @return this builder for chaining.
*/
Mob<T> spawnRestriction(SpawnRestriction.Location location, Heightmap.Type heightmap, SpawnRestriction.SpawnPredicate<T> spawnPredicate);
/**
* Sets the default attributes for a type of mob entity.
*
* @param defaultAttributeBuilder a function to generate the default attribute builder from the entity type
* @return this builder for chaining
*/
@Override
Mob<T> defaultAttributes(Supplier<DefaultAttributeContainer.Builder> defaultAttributeBuilder);
}
}
}

View file

@ -18,6 +18,7 @@ package net.fabricmc.fabric.api.object.builder.v1.entity;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import com.google.common.collect.ImmutableSet;
import org.jetbrains.annotations.Nullable;
@ -33,19 +34,13 @@ import net.minecraft.entity.SpawnRestriction;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.resource.featuretoggle.FeatureFlag;
import net.minecraft.resource.featuretoggle.FeatureFlags;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.world.Heightmap;
import net.minecraft.world.World;
import net.fabricmc.fabric.impl.object.builder.FabricEntityType;
/**
* Extended version of {@link EntityType.Builder} with added registration for
* server-&gt;client entity tracking values.
*
* @param <T> Entity class.
* @deprecated replace with {@link EntityType.Builder}
*/
@Deprecated
public class FabricEntityTypeBuilder<T extends Entity> {
private SpawnGroup spawnGroup;
private EntityType.EntityFactory<T> factory;
@ -59,7 +54,8 @@ public class FabricEntityTypeBuilder<T extends Entity> {
private EntityDimensions dimensions = EntityDimensions.changing(-1.0f, -1.0f);
private ImmutableSet<Block> specificSpawnBlocks = ImmutableSet.of();
private FeatureSet requiredFeatures = FeatureFlags.VANILLA_FEATURES;
@Nullable
private FeatureFlag[] requiredFeatures = null;
protected FabricEntityTypeBuilder(SpawnGroup spawnGroup, EntityType.EntityFactory<T> factory) {
this.spawnGroup = spawnGroup;
@ -75,7 +71,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* @param <T> the type of entity
*
* @return a new entity type builder
* @deprecated use {@link EntityType.Builder#create(SpawnGroup)}
*/
@Deprecated
public static <T extends Entity> FabricEntityTypeBuilder<T> create() {
return create(SpawnGroup.MISC);
}
@ -87,7 +85,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* @param <T> the type of entity
*
* @return a new entity type builder
* @deprecated use {@link EntityType.Builder#create(SpawnGroup)}
*/
@Deprecated
public static <T extends Entity> FabricEntityTypeBuilder<T> create(SpawnGroup spawnGroup) {
return create(spawnGroup, FabricEntityTypeBuilder::emptyFactory);
}
@ -100,7 +100,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* @param <T> the type of entity
*
* @return a new entity type builder
* @deprecated use {@link EntityType.Builder#create(EntityType.EntityFactory, SpawnGroup)}
*/
@Deprecated
public static <T extends Entity> FabricEntityTypeBuilder<T> create(SpawnGroup spawnGroup, EntityType.EntityFactory<T> factory) {
return new FabricEntityTypeBuilder<>(spawnGroup, factory);
}
@ -113,7 +115,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* @param <T> the type of entity
*
* @return a new living entity type builder
* @deprecated use {@link FabricEntityType.Builder#createLiving(UnaryOperator)}
*/
@Deprecated
public static <T extends LivingEntity> FabricEntityTypeBuilder.Living<T> createLiving() {
return new FabricEntityTypeBuilder.Living<>(SpawnGroup.MISC, FabricEntityTypeBuilder::emptyFactory);
}
@ -124,6 +128,7 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* @param <T> the type of entity
*
* @return a new mob entity type builder
* @deprecated use {@link FabricEntityType.Builder#createMob(UnaryOperator)}
*/
public static <T extends MobEntity> FabricEntityTypeBuilder.Mob<T> createMob() {
return new FabricEntityTypeBuilder.Mob<>(SpawnGroup.MISC, FabricEntityTypeBuilder::emptyFactory);
@ -133,12 +138,14 @@ public class FabricEntityTypeBuilder<T extends Entity> {
return null;
}
@Deprecated
public FabricEntityTypeBuilder<T> spawnGroup(SpawnGroup group) {
Objects.requireNonNull(group, "Spawn group cannot be null");
this.spawnGroup = group;
return this;
}
@Deprecated
public <N extends T> FabricEntityTypeBuilder<N> entityFactory(EntityType.EntityFactory<N> factory) {
Objects.requireNonNull(factory, "Entity Factory cannot be null");
this.factory = (EntityType.EntityFactory<T>) factory;
@ -149,12 +156,18 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* Whether this entity type is summonable using the {@code /summon} command.
*
* @return this builder for chaining
* @deprecated use {@link EntityType.Builder#disableSummon()}
*/
@Deprecated
public FabricEntityTypeBuilder<T> disableSummon() {
this.summonable = false;
return this;
}
/**
* @deprecated use {@link EntityType.Builder#disableSaving()}
*/
@Deprecated
public FabricEntityTypeBuilder<T> disableSaving() {
this.saveable = false;
return this;
@ -164,7 +177,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* Sets this entity type to be fire immune.
*
* @return this builder for chaining
* @deprecated use {@link EntityType.Builder#makeFireImmune()}
*/
@Deprecated
public FabricEntityTypeBuilder<T> fireImmune() {
this.fireImmune = true;
return this;
@ -174,7 +189,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* Sets whether this entity type can be spawned far away from a player.
*
* @return this builder for chaining
* @deprecated use {@link EntityType.Builder#spawnableFarFromPlayer()}
*/
@Deprecated
public FabricEntityTypeBuilder<T> spawnableFarFromPlayer() {
this.spawnableFarFromPlayer = true;
return this;
@ -186,7 +203,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* @param dimensions the dimensions representing the entity's size
*
* @return this builder for chaining
* @deprecated use {@link EntityType.Builder#setDimensions(float, float)}
*/
@Deprecated
public FabricEntityTypeBuilder<T> dimensions(EntityDimensions dimensions) {
Objects.requireNonNull(dimensions, "Cannot set null dimensions");
this.dimensions = dimensions;
@ -218,7 +237,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* @param range the tracking range in chunks
*
* @return this builder for chaining
* @deprecated use {@link FabricEntityTypeBuilder#trackRangeBlocks(int)}
*/
@Deprecated
public FabricEntityTypeBuilder<T> trackRangeChunks(int range) {
this.trackRange = range;
return this;
@ -230,16 +251,26 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* @param range the tracking range in blocks
*
* @return this builder for chaining
* @deprecated use {@link FabricEntityTypeBuilder#trackRangeChunks(int)}
*/
@Deprecated
public FabricEntityTypeBuilder<T> trackRangeBlocks(int range) {
return trackRangeChunks((range + 15) / 16);
}
/**
* @deprecated use {@link FabricEntityTypeBuilder#trackRangeBlocks(int)}
*/
@Deprecated
public FabricEntityTypeBuilder<T> trackedUpdateRate(int rate) {
this.trackedUpdateRate = rate;
return this;
}
/**
* @deprecated use {@link FabricEntityTypeBuilder#trackRangeBlocks(int)}
*/
@Deprecated
public FabricEntityTypeBuilder<T> forceTrackedVelocityUpdates(boolean forceTrackedVelocityUpdates) {
this.forceTrackedVelocityUpdates = forceTrackedVelocityUpdates;
return this;
@ -250,7 +281,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
*
* @param blocks the blocks the entity can spawn on
* @return this builder for chaining
* @deprecated use {@link EntityType.Builder#allowSpawningInside(Block...)}
*/
@Deprecated
public FabricEntityTypeBuilder<T> specificSpawnBlocks(Block... blocks) {
this.specificSpawnBlocks = ImmutableSet.copyOf(blocks);
return this;
@ -261,9 +294,11 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* the entity cannot be spawned, and existing ones will despawn immediately.
* @param requiredFeatures the features
* @return this builder for chaining
* @deprecated use {@link EntityType.Builder#requires(FeatureFlag...)}
*/
@Deprecated
public FabricEntityTypeBuilder<T> requires(FeatureFlag... requiredFeatures) {
this.requiredFeatures = FeatureFlags.FEATURE_MANAGER.featureSetOf(requiredFeatures);
this.requiredFeatures = requiredFeatures;
return this;
}
@ -271,19 +306,50 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* Creates the entity type.
*
* @return a new {@link EntityType}
* @deprecated use {@link EntityType.Builder#build()}
*/
@Deprecated
public EntityType<T> build() {
// Modded DFU is a dream, currently not possible without screwing it up.
EntityType.Builder<T> builder = EntityType.Builder.create(this.factory, this.spawnGroup)
.allowSpawningInside(specificSpawnBlocks.toArray(Block[]::new))
.maxTrackingRange(this.trackRange)
.trackingTickInterval(this.trackedUpdateRate)
.setDimensions(this.dimensions.width, this.dimensions.height);
//TODO 1.20.5, new field
return new FabricEntityType<>(this.factory, this.spawnGroup, this.saveable, this.summonable, this.fireImmune, this.spawnableFarFromPlayer, this.specificSpawnBlocks, dimensions, 1, trackRange, trackedUpdateRate, forceTrackedVelocityUpdates, this.requiredFeatures);
if (!this.saveable) {
builder = builder.disableSaving();
}
if (!this.summonable) {
builder = builder.disableSummon();
}
if (this.fireImmune) {
builder = builder.makeFireImmune();
}
if (this.spawnableFarFromPlayer) {
builder = builder.spawnableFarFromPlayer();
}
if (this.requiredFeatures != null) {
builder = builder.requires(this.requiredFeatures);
}
if (this.forceTrackedVelocityUpdates != null) {
builder = builder.alwaysUpdateVelocity(this.forceTrackedVelocityUpdates);
}
return builder.build(null);
}
/**
* An extended version of {@link FabricEntityTypeBuilder} with support for features on present on {@link LivingEntity living entities}, such as default attributes.
*
* @param <T> Entity class.
* @deprecated use {@link EntityType.Builder#createLiving(UnaryOperator)}
*/
@Deprecated
public static class Living<T extends LivingEntity> extends FabricEntityTypeBuilder<T> {
@Nullable
private Supplier<DefaultAttributeContainer.Builder> defaultAttributeBuilder;
@ -399,13 +465,16 @@ public class FabricEntityTypeBuilder<T extends Entity> {
*
* @param defaultAttributeBuilder a function to generate the default attribute builder from the entity type
* @return this builder for chaining
* @deprecated use {@link FabricEntityType.Builder.Living#defaultAttributes(Supplier)}
*/
@Deprecated
public FabricEntityTypeBuilder.Living<T> defaultAttributes(Supplier<DefaultAttributeContainer.Builder> defaultAttributeBuilder) {
Objects.requireNonNull(defaultAttributeBuilder, "Cannot set null attribute builder");
this.defaultAttributeBuilder = defaultAttributeBuilder;
return this;
}
@Deprecated
@Override
public EntityType<T> build() {
final EntityType<T> type = super.build();
@ -423,6 +492,7 @@ public class FabricEntityTypeBuilder<T extends Entity> {
*
* @param <T> Entity class.
*/
@Deprecated
public static class Mob<T extends MobEntity> extends FabricEntityTypeBuilder.Living<T> {
private SpawnLocation spawnLocation;
private Heightmap.Type restrictionHeightmap;
@ -536,7 +606,9 @@ public class FabricEntityTypeBuilder<T extends Entity> {
* <p>This is used by mobs to determine whether Minecraft should spawn an entity within a certain context.
*
* @return this builder for chaining.
* @deprecated use {@link FabricEntityType.Builder.Mob#spawnRestriction(SpawnRestriction.Location, Heightmap.Type, SpawnRestriction.SpawnPredicate)}
*/
@Deprecated
public FabricEntityTypeBuilder.Mob<T> spawnRestriction(SpawnLocation spawnLocation, Heightmap.Type heightmap, SpawnRestriction.SpawnPredicate<T> spawnPredicate) {
this.spawnLocation = Objects.requireNonNull(spawnLocation, "Spawn location cannot be null.");
this.restrictionHeightmap = Objects.requireNonNull(heightmap, "Heightmap type cannot be null.");

View file

@ -1,44 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.object.builder;
import com.google.common.collect.ImmutableSet;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.resource.featuretoggle.FeatureSet;
public class FabricEntityType<T extends Entity> extends EntityType<T> {
private final Boolean alwaysUpdateVelocity;
public FabricEntityType(EntityType.EntityFactory<T> factory, SpawnGroup spawnGroup, boolean bl, boolean summonable, boolean fireImmune, boolean spawnableFarFromPlayer, ImmutableSet<Block> spawnBlocks, EntityDimensions entityDimensions, float field_50125, int maxTrackDistance, int trackTickInterval, Boolean alwaysUpdateVelocity, FeatureSet featureSet) {
super(factory, spawnGroup, bl, summonable, fireImmune, spawnableFarFromPlayer, spawnBlocks, entityDimensions, field_50125, maxTrackDistance, trackTickInterval, featureSet);
this.alwaysUpdateVelocity = alwaysUpdateVelocity;
}
@Override
public boolean alwaysUpdateVelocity() {
if (alwaysUpdateVelocity != null) {
return alwaysUpdateVelocity;
}
return super.alwaysUpdateVelocity();
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.object.builder;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import org.jetbrains.annotations.Nullable;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.SpawnRestriction;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.world.Heightmap;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityType;
public interface FabricEntityTypeImpl {
void fabric_setAlwaysUpdateVelocity(Boolean alwaysUpdateVelocity);
interface Builder {
void fabric_setLivingEntityBuilder(Living<? extends LivingEntity> livingBuilder);
void fabric_setMobEntityBuilder(Mob<? extends MobEntity> mobBuilder);
static <T extends LivingEntity> EntityType.Builder<T> createLiving(EntityType.EntityFactory<T> factory, SpawnGroup spawnGroup, UnaryOperator<FabricEntityType.Builder.Living<T>> livingBuilder) {
EntityType.Builder<T> builder = EntityType.Builder.create(factory, spawnGroup);
Living<T> builderImpl = new Living<>();
livingBuilder.apply(builderImpl);
((Builder) builder).fabric_setLivingEntityBuilder(builderImpl);
return builder;
}
static <T extends MobEntity> EntityType.Builder<T> createMob(EntityType.EntityFactory<T> factory, SpawnGroup spawnGroup, UnaryOperator<FabricEntityType.Builder.Mob<T>> mobBuilder) {
EntityType.Builder<T> builder = EntityType.Builder.create(factory, spawnGroup);
Mob<T> builderImpl = new Mob<>();
mobBuilder.apply(builderImpl);
((Builder) builder).fabric_setMobEntityBuilder(builderImpl);
return builder;
}
sealed class Living<T extends LivingEntity> implements FabricEntityType.Builder.Living<T> permits Mob {
@Nullable
private Supplier<DefaultAttributeContainer.Builder> defaultAttributeBuilder;
@Override
public FabricEntityType.Builder.Living<T> defaultAttributes(Supplier<DefaultAttributeContainer.Builder> defaultAttributeBuilder) {
Objects.requireNonNull(defaultAttributeBuilder, "Cannot set null attribute builder");
this.defaultAttributeBuilder = defaultAttributeBuilder;
return this;
}
public void onBuild(EntityType<T> type) {
if (this.defaultAttributeBuilder != null) {
FabricDefaultAttributeRegistry.register(type, this.defaultAttributeBuilder.get());
}
}
}
final class Mob<T extends MobEntity> extends Living<T> implements FabricEntityType.Builder.Mob<T> {
private SpawnRestriction.Location restrictionLocation;
private Heightmap.Type restrictionHeightmap;
private SpawnRestriction.SpawnPredicate<T> spawnPredicate;
@Override
public FabricEntityType.Builder.Mob<T> spawnRestriction(SpawnRestriction.Location location, Heightmap.Type heightmap, SpawnRestriction.SpawnPredicate<T> spawnPredicate) {
this.restrictionLocation = Objects.requireNonNull(location, "Location cannot be null.");
this.restrictionHeightmap = Objects.requireNonNull(heightmap, "Heightmap type cannot be null.");
this.spawnPredicate = Objects.requireNonNull(spawnPredicate, "Spawn predicate cannot be null.");
return this;
}
@Override
public FabricEntityType.Builder.Mob<T> defaultAttributes(Supplier<DefaultAttributeContainer.Builder> defaultAttributeBuilder) {
super.defaultAttributes(defaultAttributeBuilder);
return this;
}
public void onBuild(EntityType<T> type) {
super.onBuild(type);
if (this.spawnPredicate != null) {
SpawnRestriction.register(type, this.restrictionLocation, this.restrictionHeightmap, this.spawnPredicate);
}
}
}
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.object.builder;
import com.mojang.datafixers.types.Type;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityType;
@Mixin(BlockEntityType.Builder.class)
public abstract class BlockEntityTypeBuilderMixin<T extends BlockEntity> implements FabricBlockEntityType.Builder<T> {
@Shadow
public abstract BlockEntityType<T> build(Type<?> type);
@Override
public BlockEntityType<T> build() {
return build(null);
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.object.builder;
import java.util.Objects;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.types.Type;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityType;
import net.fabricmc.fabric.impl.object.builder.FabricEntityTypeImpl;
@Mixin(EntityType.Builder.class)
public abstract class EntityTypeBuilderMixin<T extends Entity> implements FabricEntityType.Builder<T>, FabricEntityTypeImpl.Builder {
@Shadow
public abstract EntityType<T> build(String id);
@Unique
private Boolean alwaysUpdateVelocity = null;
@Unique
private FabricEntityTypeImpl.Builder.Living<? extends LivingEntity> livingBuilder = null;
@Unique
private FabricEntityTypeImpl.Builder.Mob<? extends MobEntity> mobBuilder = null;
@Override
public EntityType.Builder<T> alwaysUpdateVelocity(boolean forceTrackedVelocityUpdates) {
alwaysUpdateVelocity = forceTrackedVelocityUpdates;
return (EntityType.Builder<T>) (Object) this;
}
@Override
public EntityType<T> build() {
return build(null);
}
@Inject(method = "build", at = @At("RETURN"))
private void applyChildBuilders(String id, CallbackInfoReturnable<EntityType<T>> cir) {
if (!(cir.getReturnValue() instanceof FabricEntityTypeImpl entityType)) {
throw new IllegalStateException();
}
entityType.fabric_setAlwaysUpdateVelocity(alwaysUpdateVelocity);
if (livingBuilder != null) {
livingBuilder.onBuild(castLiving(cir.getReturnValue()));
}
if (mobBuilder != null) {
mobBuilder.onBuild(castMob(cir.getReturnValue()));
}
}
@SuppressWarnings("unchecked")
@Unique
private static <T extends LivingEntity> EntityType<T> castLiving(EntityType<?> type) {
return (EntityType<T>) type;
}
@SuppressWarnings("unchecked")
@Unique
private static <T extends MobEntity> EntityType<T> castMob(EntityType<?> type) {
return (EntityType<T>) type;
}
@WrapOperation(method = "build", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Util;getChoiceType(Lcom/mojang/datafixers/DSL$TypeReference;Ljava/lang/String;)Lcom/mojang/datafixers/types/Type;"))
private @Nullable Type<?> allowNullId(DSL.TypeReference typeReference, String id, Operation<Type<?>> original) {
if (id == null) {
return null;
}
return original.call(typeReference, id);
}
@Override
public void fabric_setLivingEntityBuilder(FabricEntityTypeImpl.Builder.Living<? extends LivingEntity> livingBuilder) {
Objects.requireNonNull(livingBuilder, "Cannot set null living entity builder");
this.livingBuilder = livingBuilder;
}
@Override
public void fabric_setMobEntityBuilder(FabricEntityTypeImpl.Builder.Mob<? extends MobEntity> mobBuilder) {
Objects.requireNonNull(mobBuilder, "Cannot set null mob entity builder");
this.mobBuilder = mobBuilder;
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.object.builder;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.entity.EntityType;
import net.fabricmc.fabric.impl.object.builder.FabricEntityTypeImpl;
@Mixin(EntityType.class)
public abstract class EntityTypeMixin implements FabricEntityTypeImpl {
@Unique
private Boolean alwaysUpdateVelocity;
@Inject(method = "alwaysUpdateVelocity", at = @At("HEAD"), cancellable = true)
public void alwaysUpdateVelocity(CallbackInfoReturnable<Boolean> cir) {
if (alwaysUpdateVelocity != null) {
cir.setReturnValue(alwaysUpdateVelocity);
}
}
@Override
public void fabric_setAlwaysUpdateVelocity(Boolean alwaysUpdateVelocity) {
this.alwaysUpdateVelocity = alwaysUpdateVelocity;
}
}

View file

@ -5,9 +5,12 @@
"mixins": [
"AbstractBlockAccessor",
"AbstractBlockSettingsAccessor",
"BlockEntityTypeBuilderMixin",
"DefaultAttributeRegistryAccessor",
"DefaultAttributeRegistryMixin",
"DetectorRailBlockMixin",
"EntityTypeBuilderMixin",
"EntityTypeMixin",
"PersistentStateManagerMixin",
"TradeOffersTypeAwareBuyForOneEmeraldFactoryMixin"
],

View file

@ -29,6 +29,10 @@
],
"accessWidener" : "fabric-object-builder-api-v1.accesswidener",
"custom": {
"fabric-api:module-lifecycle": "stable"
"fabric-api:module-lifecycle": "stable",
"loom:injected_interfaces": {
"net/minecraft/class_1299\u0024class_1300": ["net/fabricmc/fabric/api/object/builder/v1/entity/FabricEntityType\u0024Builder<TT;>"],
"net/minecraft/class_2591\u0024class_2592": ["net/fabricmc/fabric/api/object/builder/v1/block/entity/FabricBlockEntityType\u0024Builder<TT;>"]
}
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.test.object.builder;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import net.minecraft.Bootstrap;
import net.minecraft.SharedConstants;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.SpawnRestriction;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.DefaultAttributeRegistry;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.passive.PigEntity;
import net.minecraft.world.Heightmap;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityType;
public class FabricEntityTypeTest {
@BeforeAll
static void beforeAll() {
SharedConstants.createGameVersion();
Bootstrap.initialize();
}
@Test
void buildEntityType() {
EntityType<Entity> type = EntityType.Builder.create(SpawnGroup.MISC)
.alwaysUpdateVelocity(true)
.build();
assertNotNull(type);
assertTrue(type.alwaysUpdateVelocity());
}
@Test
void buildLivingEntityType() {
EntityType<LivingEntity> type = FabricEntityType.Builder.createLiving((t, w) -> null, SpawnGroup.MISC, living -> living
.defaultAttributes(FabricEntityTypeTest::createAttributes)
).build();
assertNotNull(type);
assertNotNull(DefaultAttributeRegistry.get(type));
}
@Test
void buildMobEntityType() {
EntityType<MobEntity> type = FabricEntityType.Builder.createMob((t, w) -> null, SpawnGroup.MISC, mob -> mob
.spawnRestriction(SpawnRestriction.Location.ON_GROUND, Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, PigEntity::canMobSpawn)
.defaultAttributes(FabricEntityTypeTest::createAttributes)
).build();
assertNotNull(type);
assertEquals(SpawnRestriction.Location.ON_GROUND, SpawnRestriction.getLocation(type));
assertNotNull(DefaultAttributeRegistry.get(type));
}
private static DefaultAttributeContainer.Builder createAttributes() {
return MobEntity.createMobAttributes()
.add(EntityAttributes.GENERIC_MAX_HEALTH, 10.0)
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25);
}
}