Skip to content

Commit 84dd963

Browse files
committed
Add EntityType and MenuType registrars
1 parent 9fd5e01 commit 84dd963

File tree

6 files changed

+301
-0
lines changed

6 files changed

+301
-0
lines changed

src/main/java/dev/apexstudios/registree/Registree.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
import com.google.errorprone.annotations.CanIgnoreReturnValue;
55
import dev.apexstudios.registree.registrar.BlockEntityTypeRegistrar;
66
import dev.apexstudios.registree.registrar.BlockRegistrar;
7+
import dev.apexstudios.registree.registrar.EntityTypeRegistrar;
78
import dev.apexstudios.registree.registrar.GameRuleRegistrar;
89
import dev.apexstudios.registree.registrar.ItemRegistrar;
10+
import dev.apexstudios.registree.registrar.MenuTypeRegistrar;
911
import dev.apexstudios.registree.registrar.Registrar;
1012
import java.util.Map;
1113
import java.util.Objects;
@@ -36,6 +38,8 @@ public Registree(String namespace, Consumer<Registrars> registrarsConsumer) {
3638
registrars.with(Registries.BLOCK, BlockRegistrar::new);
3739
registrars.with(Registries.BLOCK_ENTITY_TYPE, BlockEntityTypeRegistrar::new);
3840
registrars.with(Registries.GAME_RULE, GameRuleRegistrar::new);
41+
registrars.with(Registries.ENTITY_TYPE, EntityTypeRegistrar::new);
42+
registrars.with(Registries.MENU, MenuTypeRegistrar::new);
3943

4044
registrarsConsumer.accept(registrars);
4145
});
@@ -92,6 +96,14 @@ public GameRuleRegistrar gameRules() {
9296
return (GameRuleRegistrar) registrarOrThrow(Registries.GAME_RULE);
9397
}
9498

99+
public EntityTypeRegistrar entityTypes() {
100+
return (EntityTypeRegistrar) registrarOrThrow(Registries.ENTITY_TYPE);
101+
}
102+
103+
public MenuTypeRegistrar menuTypes() {
104+
return (MenuTypeRegistrar) registrarOrThrow(Registries.MENU);
105+
}
106+
95107
public void registerEvents(IEventBus modBus) {
96108
this.modBus.notify(modBus);
97109
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package dev.apexstudios.registree.builder;
2+
3+
import com.google.common.collect.HashMultimap;
4+
import com.google.common.collect.Multimap;
5+
import dev.apexstudios.registree.holder.DeferredEntityType;
6+
import dev.apexstudios.registree.registrar.EntityTypeRegistrar;
7+
import java.util.function.BiConsumer;
8+
import java.util.function.Consumer;
9+
import java.util.function.Function;
10+
import net.minecraft.client.renderer.entity.EntityRendererProvider;
11+
import net.minecraft.resources.Identifier;
12+
import net.minecraft.world.entity.Entity;
13+
import net.minecraft.world.entity.EntityType;
14+
import net.minecraft.world.entity.LivingEntity;
15+
import net.minecraft.world.entity.MobCategory;
16+
import net.minecraft.world.entity.SpawnPlacementType;
17+
import net.minecraft.world.entity.SpawnPlacements;
18+
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
19+
import net.minecraft.world.level.levelgen.Heightmap;
20+
import net.neoforged.neoforge.capabilities.EntityCapability;
21+
import net.neoforged.neoforge.capabilities.ICapabilityProvider;
22+
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
23+
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
24+
import net.neoforged.neoforge.client.event.RegisterEntitySpectatorShadersEvent;
25+
import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent;
26+
import net.neoforged.neoforge.event.entity.RegisterSpawnPlacementsEvent;
27+
import org.jspecify.annotations.Nullable;
28+
29+
public class EntityTypeBuilder<TEntity extends Entity> extends Builder<EntityTypeRegistrar, EntityType<?>, EntityType<TEntity>, DeferredEntityType<TEntity>, EntityTypeBuilder.Context<TEntity>> {
30+
private final EntityType.EntityFactory<TEntity> factory;
31+
private final MobCategory category;
32+
private BiConsumer<Context<TEntity>, EntityType.Builder<TEntity>> propertiesModifier = (context, builder) -> { };
33+
private @Nullable EntityRendererProvider<TEntity> rendererProvider = null;
34+
private final Multimap<EntityCapability<?, ?>, ICapabilityProvider<TEntity, ?, ?>> capabilities = HashMultimap.create();
35+
private @Nullable Function<Context<TEntity>, Identifier> spectatorShader = null;
36+
private @Nullable AttributeSupplier attributes = null;
37+
private @Nullable SpawnPlacement<TEntity> spawnPlacement = null;
38+
39+
public EntityTypeBuilder(EntityTypeRegistrar registrar, String identifier, EntityType.EntityFactory<TEntity> factory, MobCategory category) {
40+
super(registrar, identifier, DeferredEntityType::createEntityType, Context::new);
41+
42+
this.factory = factory;
43+
this.category = category;
44+
}
45+
46+
public EntityTypeBuilder<TEntity> properties(BiConsumer<Context<TEntity>, EntityType.Builder<TEntity>> propertiesModifier) {
47+
this.propertiesModifier = this.propertiesModifier.andThen(propertiesModifier);
48+
return this;
49+
}
50+
51+
public EntityTypeBuilder<TEntity> properties(Consumer<EntityType.Builder<TEntity>> propertiesModifier) {
52+
return properties((context, builder) -> propertiesModifier.accept(builder));
53+
}
54+
55+
public EntityTypeBuilder<TEntity> renderer(EntityRendererProvider<TEntity> rendererProvider) {
56+
this.rendererProvider = rendererProvider;
57+
return this;
58+
}
59+
60+
public <TCapability, TContext extends @Nullable Object> EntityTypeBuilder<TEntity> capability(EntityCapability<TCapability, TContext> capability, ICapabilityProvider<TEntity, TContext, TCapability> provider) {
61+
capabilities.put(capability, provider);
62+
return this;
63+
}
64+
65+
@SuppressWarnings("unchecked")
66+
private <TCapability, TContext extends @Nullable Object> void registerCapability(RegisterCapabilitiesEvent event, Context<TEntity> context, EntityCapability<TCapability, TContext> capability) {
67+
for(var provider : capabilities.get(capability)) {
68+
event.registerEntity(capability, context.get(), (ICapabilityProvider<TEntity, TContext, TCapability>) provider);
69+
}
70+
}
71+
72+
public EntityTypeBuilder<TEntity> spectatorShader(Identifier spectatorShader) {
73+
this.spectatorShader = context -> spectatorShader;
74+
return this;
75+
}
76+
77+
public EntityTypeBuilder<TEntity> spectatorShader(String spectatorShader) {
78+
this.spectatorShader = context -> context.registree().registryName(spectatorShader);
79+
return this;
80+
}
81+
82+
public EntityTypeBuilder<TEntity> attributes(AttributeSupplier attributes) {
83+
this.attributes = attributes;
84+
return this;
85+
}
86+
87+
public EntityTypeBuilder<TEntity> spawnPlacement(@Nullable SpawnPlacementType type, Heightmap.@Nullable Types heightmap, SpawnPlacements.SpawnPredicate<TEntity> predicate) {
88+
spawnPlacement = new SpawnPlacement<>(type, heightmap, predicate);
89+
return this;
90+
}
91+
92+
public EntityTypeBuilder<TEntity> spawnPlacement(Heightmap.@Nullable Types heightmap, SpawnPlacements.SpawnPredicate<TEntity> predicate) {
93+
return spawnPlacement(null, heightmap, predicate);
94+
}
95+
96+
public EntityTypeBuilder<TEntity> spawnPlacement(@Nullable SpawnPlacementType type, SpawnPlacements.SpawnPredicate<TEntity> predicate) {
97+
return spawnPlacement(type, null, predicate);
98+
}
99+
100+
public EntityTypeBuilder<TEntity> spawnPlacement(SpawnPlacements.SpawnPredicate<TEntity> predicate) {
101+
return spawnPlacement(null, null, predicate);
102+
}
103+
104+
@Override
105+
protected EntityType<TEntity> compile(Context<TEntity> context) {
106+
var builder = EntityType.Builder.of(factory, category);
107+
propertiesModifier.accept(context, builder);
108+
return builder.build(context.registryKey());
109+
}
110+
111+
@SuppressWarnings("unchecked")
112+
@Override
113+
protected void finalize(Context<TEntity> context) {
114+
if(rendererProvider != null) {
115+
context.registree().event(EntityRenderersEvent.RegisterRenderers.class, event -> {
116+
event.registerEntityRenderer(context.get(), rendererProvider);
117+
rendererProvider = null;
118+
});
119+
}
120+
121+
if(!capabilities.isEmpty()) {
122+
context.registree().event(RegisterCapabilitiesEvent.class, event -> {
123+
for(var capability : capabilities.keySet()) {
124+
registerCapability(event, context, capability);
125+
}
126+
127+
capabilities.clear();
128+
});
129+
}
130+
131+
if(spectatorShader != null) {
132+
context.registree().event(RegisterEntitySpectatorShadersEvent.class, event -> {
133+
event.register(context.get(), spectatorShader.apply(context));
134+
spectatorShader = null;
135+
});
136+
}
137+
138+
if(attributes != null) {
139+
context.registree().event(EntityAttributeCreationEvent.class, event -> {
140+
event.put((EntityType<? extends LivingEntity>) context.get(), attributes);
141+
attributes = null;
142+
});
143+
}
144+
145+
if(spawnPlacement != null) {
146+
context.registree().event(RegisterSpawnPlacementsEvent.class, event -> {
147+
event.register(context.get(), spawnPlacement.type, spawnPlacement.heightmap, spawnPlacement.predicate, RegisterSpawnPlacementsEvent.Operation.REPLACE);
148+
spawnPlacement = null;
149+
});
150+
}
151+
}
152+
153+
public static final class Context<TEntity extends Entity> extends Builder.Context<EntityTypeRegistrar, EntityType<?>, EntityType<TEntity>, DeferredEntityType<TEntity>> {
154+
private Context(EntityTypeRegistrar registrar, DeferredEntityType<TEntity> holder) {
155+
super(registrar, holder);
156+
}
157+
}
158+
159+
private record SpawnPlacement<TEntity extends Entity>(@Nullable SpawnPlacementType type, Heightmap.@Nullable Types heightmap, SpawnPlacements.SpawnPredicate<TEntity> predicate) { }
160+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package dev.apexstudios.registree.holder;
2+
3+
import net.minecraft.core.registries.Registries;
4+
import net.minecraft.resources.Identifier;
5+
import net.minecraft.resources.ResourceKey;
6+
import net.minecraft.world.entity.Entity;
7+
import net.minecraft.world.entity.EntityType;
8+
import net.neoforged.neoforge.registries.DeferredHolder;
9+
10+
public class DeferredEntityType<TEntity extends Entity> extends DeferredHolder<EntityType<?>, EntityType<TEntity>> {
11+
protected DeferredEntityType(ResourceKey<EntityType<?>> registryKey) {
12+
super(registryKey);
13+
}
14+
15+
public static <TEntity extends Entity> DeferredEntityType<TEntity> createEntityType(ResourceKey<EntityType<?>> registryKey) {
16+
return new DeferredEntityType<>(registryKey);
17+
}
18+
19+
public static <TEntity extends Entity> DeferredEntityType<TEntity> createEntityType(Identifier registryName) {
20+
return createEntityType(ResourceKey.create(Registries.ENTITY_TYPE, registryName));
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package dev.apexstudios.registree.holder;
2+
3+
import net.minecraft.core.registries.Registries;
4+
import net.minecraft.resources.Identifier;
5+
import net.minecraft.resources.ResourceKey;
6+
import net.minecraft.world.inventory.AbstractContainerMenu;
7+
import net.minecraft.world.inventory.MenuType;
8+
import net.neoforged.neoforge.registries.DeferredHolder;
9+
10+
public class DeferredMenuType<TMenu extends AbstractContainerMenu> extends DeferredHolder<MenuType<?>, MenuType<TMenu>> {
11+
protected DeferredMenuType(ResourceKey<MenuType<?>> key) {
12+
super(key);
13+
}
14+
15+
public static <TMenu extends AbstractContainerMenu> DeferredMenuType<TMenu> createMenuType(ResourceKey<MenuType<?>> registryKey) {
16+
return new DeferredMenuType<>(registryKey);
17+
}
18+
19+
public static <TMenu extends AbstractContainerMenu> DeferredMenuType<TMenu> createMenuType(Identifier registryName) {
20+
return createMenuType(ResourceKey.create(Registries.MENU, registryName));
21+
}
22+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package dev.apexstudios.registree.registrar;
2+
3+
import dev.apexstudios.registree.Registree;
4+
import dev.apexstudios.registree.builder.EntityTypeBuilder;
5+
import dev.apexstudios.registree.holder.DeferredEntityType;
6+
import java.util.function.Consumer;
7+
import net.minecraft.core.registries.Registries;
8+
import net.minecraft.world.entity.Entity;
9+
import net.minecraft.world.entity.EntityType;
10+
import net.minecraft.world.entity.MobCategory;
11+
import org.apache.commons.lang3.function.Consumers;
12+
13+
public class EntityTypeRegistrar extends Registrar<EntityType<?>> {
14+
public EntityTypeRegistrar(Registree registree) {
15+
super(registree, Registries.ENTITY_TYPE);
16+
}
17+
18+
public <TEntity extends Entity> EntityTypeBuilder<TEntity> builder(String identifier, EntityType.EntityFactory<TEntity> factory, MobCategory category) {
19+
return new EntityTypeBuilder<>(this, identifier, factory, category);
20+
}
21+
22+
public <TEntity extends Entity> DeferredEntityType<TEntity> register(String identifier, EntityType.EntityFactory<TEntity> factory, MobCategory category, Consumer<EntityType.Builder<TEntity>> propertiesModifier) {
23+
return registerForHolder(identifier, registryName -> {
24+
var builder = EntityType.Builder.of(factory, category);
25+
propertiesModifier.accept(builder);
26+
return builder.build(registryKey(registryName));
27+
}, DeferredEntityType::createEntityType);
28+
}
29+
30+
public <TEntity extends Entity> DeferredEntityType<TEntity> register(String identifier, EntityType.EntityFactory<TEntity> factory, MobCategory category) {
31+
return register(identifier, factory, category, Consumers.nop());
32+
}
33+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package dev.apexstudios.registree.registrar;
2+
3+
import com.google.common.collect.Maps;
4+
import dev.apexstudios.registree.Registree;
5+
import dev.apexstudios.registree.holder.DeferredMenuType;
6+
import java.util.Map;
7+
import java.util.function.Supplier;
8+
import net.minecraft.client.gui.screens.MenuScreens;
9+
import net.minecraft.client.gui.screens.Screen;
10+
import net.minecraft.client.gui.screens.inventory.MenuAccess;
11+
import net.minecraft.core.registries.Registries;
12+
import net.minecraft.world.flag.FeatureFlagSet;
13+
import net.minecraft.world.flag.FeatureFlags;
14+
import net.minecraft.world.inventory.AbstractContainerMenu;
15+
import net.minecraft.world.inventory.MenuType;
16+
import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent;
17+
18+
public class MenuTypeRegistrar extends Registrar<MenuType<?>> {
19+
private final Map<DeferredMenuType<?>, Supplier<? extends MenuScreens.ScreenConstructor<?, ?>>> screenFactories = Maps.newHashMap();
20+
21+
public MenuTypeRegistrar(Registree registree) {
22+
super(registree, Registries.MENU);
23+
24+
registree.event(RegisterMenuScreensEvent.class, event -> {
25+
screenFactories.keySet().forEach(holder -> registerScreen(event, holder));
26+
screenFactories.clear();
27+
});
28+
}
29+
30+
public <TMenu extends AbstractContainerMenu> DeferredMenuType<TMenu> register(String identifier, MenuType.MenuSupplier<TMenu> factory, FeatureFlagSet requiredFeatures) {
31+
return registerForHolder(identifier, () -> new MenuType<>(factory, requiredFeatures), DeferredMenuType::createMenuType);
32+
}
33+
34+
public <TMenu extends AbstractContainerMenu> DeferredMenuType<TMenu> register(String identifier, MenuType.MenuSupplier<TMenu> factory) {
35+
return register(identifier, factory, FeatureFlags.DEFAULT_FLAGS);
36+
}
37+
38+
public <TMenu extends AbstractContainerMenu, TScreen extends Screen & MenuAccess<TMenu>> DeferredMenuType<TMenu> register(String identifier, MenuType.MenuSupplier<TMenu> factory, FeatureFlagSet requiredFeatures, Supplier<MenuScreens.ScreenConstructor<TMenu, TScreen>> screenFactory) {
39+
var holder = register(identifier, factory, requiredFeatures);
40+
screenFactories.put(holder, screenFactory);
41+
return holder;
42+
}
43+
44+
@SuppressWarnings("unchecked")
45+
private <TMenu extends AbstractContainerMenu> void registerScreen(RegisterMenuScreensEvent event, DeferredMenuType<TMenu> holder) {
46+
var factory = screenFactories.get(holder);
47+
48+
if(factory != null) {
49+
event.register(holder.value(), (MenuScreens.ScreenConstructor<? super TMenu, ?>) factory.get());
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)