mirror of
https://github.com/architectury/architectury-api.git
synced 2026-04-03 05:57:40 -05:00
Add NetworkManager hook for Entity spawn packets (#88)
* New utility hook for creating a entity spawn packet. before every mod had to implement this in itself. * Apply suggestions from code review Co-authored-by: shedaniel <daniel@shedaniel.me> * Update common/src/main/java/me/shedaniel/architectury/networking/NetworkManager.java * Update common/src/main/java/me/shedaniel/architectury/networking/NetworkManager.java * Properly implement SpawnEntityPacket & Format style Signed-off-by: shedaniel <daniel@shedaniel.me> * Format Signed-off-by: shedaniel <daniel@shedaniel.me> * createEntitySpawnPacket -> createAddEntityPacket for mojmap consistency Signed-off-by: shedaniel <daniel@shedaniel.me> * Bump version to 1.17 Co-authored-by: Max <maxh2709@gmail.com> Co-authored-by: shedaniel <daniel@shedaniel.me>
This commit is contained in:
@@ -28,6 +28,7 @@ import net.minecraft.network.FriendlyByteBuf;
|
|||||||
import net.minecraft.network.protocol.Packet;
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -74,6 +75,20 @@ public final class NetworkManager {
|
|||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Easy to use utility method to create an entity spawn packet.
|
||||||
|
* This packet is needed everytime any mod adds a non-living entity.
|
||||||
|
* The entity should override {@link Entity#getAddEntityPacket()} to point to this method!
|
||||||
|
*
|
||||||
|
* @param entity The entity which should be spawned.
|
||||||
|
* @return The ready to use packet to spawn the entity on the client.
|
||||||
|
* @see Entity#getAddEntityPacket()
|
||||||
|
*/
|
||||||
|
@ExpectPlatform
|
||||||
|
public static Packet<?> createAddEntityPacket(Entity entity) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface NetworkReceiver {
|
public interface NetworkReceiver {
|
||||||
void receive(FriendlyByteBuf buf, PacketContext context);
|
void receive(FriendlyByteBuf buf, PacketContext context);
|
||||||
|
|||||||
@@ -20,10 +20,13 @@
|
|||||||
package me.shedaniel.architectury.init.fabric;
|
package me.shedaniel.architectury.init.fabric;
|
||||||
|
|
||||||
import me.shedaniel.architectury.event.events.client.ClientLifecycleEvent;
|
import me.shedaniel.architectury.event.events.client.ClientLifecycleEvent;
|
||||||
|
import me.shedaniel.architectury.networking.fabric.SpawnEntityPacket;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
public class ArchitecturyClient {
|
public class ArchitecturyClient {
|
||||||
public static void init() {
|
public static void init() {
|
||||||
ClientLifecycleEvent.CLIENT_SETUP.invoker().stateChanged(Minecraft.getInstance());
|
ClientLifecycleEvent.CLIENT_SETUP.invoker().stateChanged(Minecraft.getInstance());
|
||||||
|
|
||||||
|
SpawnEntityPacket.register();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import net.minecraft.network.FriendlyByteBuf;
|
|||||||
import net.minecraft.network.protocol.Packet;
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
public class NetworkManagerImpl {
|
public class NetworkManagerImpl {
|
||||||
@@ -88,6 +89,10 @@ public class NetworkManagerImpl {
|
|||||||
return ServerSidePacketRegistry.INSTANCE.canPlayerReceive(player, id);
|
return ServerSidePacketRegistry.INSTANCE.canPlayerReceive(player, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Packet<?> createAddEntityPacket(Entity entity) {
|
||||||
|
return SpawnEntityPacket.create(entity);
|
||||||
|
}
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
private static Packet<?> toC2SPacket(ResourceLocation id, FriendlyByteBuf buf) {
|
private static Packet<?> toC2SPacket(ResourceLocation id, FriendlyByteBuf buf) {
|
||||||
return ClientSidePacketRegistry.INSTANCE.toPacket(id, buf);
|
return ClientSidePacketRegistry.INSTANCE.toPacket(id, buf);
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of architectury.
|
||||||
|
* Copyright (C) 2020, 2021 architectury
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.shedaniel.architectury.networking.fabric;
|
||||||
|
|
||||||
|
import me.shedaniel.architectury.networking.NetworkManager;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see net.minecraft.network.protocol.game.ClientboundAddEntityPacket
|
||||||
|
*/
|
||||||
|
public class SpawnEntityPacket {
|
||||||
|
private static final ResourceLocation PACKET_ID = new ResourceLocation("architectury", "spawn_entity_packet");
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public static void register() {
|
||||||
|
NetworkManager.registerReceiver(NetworkManager.s2c(), PACKET_ID, SpawnEntityPacket::receive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Packet<?> create(Entity entity) {
|
||||||
|
if (entity.level.isClientSide()) {
|
||||||
|
throw new IllegalStateException("SpawnPacketUtil.create called on the logical client!");
|
||||||
|
}
|
||||||
|
FriendlyByteBuf buffer = PacketByteBufs.create();
|
||||||
|
buffer.writeVarInt(Registry.ENTITY_TYPE.getId(entity.getType()));
|
||||||
|
buffer.writeUUID(entity.getUUID());
|
||||||
|
buffer.writeVarInt(entity.getId());
|
||||||
|
Vec3 position = entity.position();
|
||||||
|
buffer.writeDouble(position.x);
|
||||||
|
buffer.writeDouble(position.y);
|
||||||
|
buffer.writeDouble(position.z);
|
||||||
|
buffer.writeFloat(entity.xRot);
|
||||||
|
buffer.writeFloat(entity.yRot);
|
||||||
|
buffer.writeFloat(entity.getYHeadRot());
|
||||||
|
Vec3 deltaMovement = entity.getDeltaMovement();
|
||||||
|
buffer.writeDouble(deltaMovement.x);
|
||||||
|
buffer.writeDouble(deltaMovement.y);
|
||||||
|
buffer.writeDouble(deltaMovement.z);
|
||||||
|
return NetworkManager.toPacket(NetworkManager.s2c(), PACKET_ID, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public static void receive(FriendlyByteBuf buf, NetworkManager.PacketContext context) {
|
||||||
|
int entityTypeId = buf.readVarInt();
|
||||||
|
UUID uuid = buf.readUUID();
|
||||||
|
int id = buf.readVarInt();
|
||||||
|
double x = buf.readDouble();
|
||||||
|
double y = buf.readDouble();
|
||||||
|
double z = buf.readDouble();
|
||||||
|
float xRot = buf.readFloat();
|
||||||
|
float yRot = buf.readFloat();
|
||||||
|
float yHeadRot = buf.readFloat();
|
||||||
|
double deltaX = buf.readDouble();
|
||||||
|
double deltaY = buf.readDouble();
|
||||||
|
double deltaZ = buf.readDouble();
|
||||||
|
context.queue(() -> {
|
||||||
|
EntityType<?> entityType = Registry.ENTITY_TYPE.byId(entityTypeId);
|
||||||
|
if (entityType == null) {
|
||||||
|
throw new IllegalStateException("Entity type (" + entityTypeId + ") is unknown, spawning at (" + x + ", " + y + ", " + z + ")");
|
||||||
|
}
|
||||||
|
if (Minecraft.getInstance().level == null) {
|
||||||
|
throw new IllegalStateException("Client world is null!");
|
||||||
|
}
|
||||||
|
Entity entity = entityType.create(Minecraft.getInstance().level);
|
||||||
|
if (entity == null) {
|
||||||
|
throw new IllegalStateException("Created entity is null!");
|
||||||
|
}
|
||||||
|
entity.setUUID(uuid);
|
||||||
|
entity.setId(id);
|
||||||
|
entity.setPacketCoordinates(x, y, z);
|
||||||
|
entity.absMoveTo(x, y, z, xRot, yRot);
|
||||||
|
entity.setYHeadRot(yHeadRot);
|
||||||
|
entity.setYBodyRot(yHeadRot);
|
||||||
|
Minecraft.getInstance().level.putNonPlayerEntity(id, entity);
|
||||||
|
entity.lerpMotion(deltaX, deltaY, deltaZ);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import net.minecraft.network.FriendlyByteBuf;
|
|||||||
import net.minecraft.network.protocol.Packet;
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
@@ -40,6 +41,7 @@ import net.minecraftforge.fml.LogicalSide;
|
|||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.network.NetworkDirection;
|
import net.minecraftforge.fml.network.NetworkDirection;
|
||||||
import net.minecraftforge.fml.network.NetworkEvent;
|
import net.minecraftforge.fml.network.NetworkEvent;
|
||||||
|
import net.minecraftforge.fml.network.NetworkHooks;
|
||||||
import net.minecraftforge.fml.network.NetworkRegistry;
|
import net.minecraftforge.fml.network.NetworkRegistry;
|
||||||
import net.minecraftforge.fml.network.event.EventNetworkChannel;
|
import net.minecraftforge.fml.network.event.EventNetworkChannel;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
@@ -148,6 +150,10 @@ public class NetworkManagerImpl {
|
|||||||
return clientReceivables.get(player).contains(id);
|
return clientReceivables.get(player).contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Packet<?> createAddEntityPacket(Entity entity){
|
||||||
|
return NetworkHooks.getEntitySpawningPacket(entity);
|
||||||
|
}
|
||||||
|
|
||||||
static FriendlyByteBuf sendSyncPacket(Map<ResourceLocation, NetworkReceiver> map) {
|
static FriendlyByteBuf sendSyncPacket(Map<ResourceLocation, NetworkReceiver> map) {
|
||||||
List<ResourceLocation> availableIds = Lists.newArrayList(map.keySet());
|
List<ResourceLocation> availableIds = Lists.newArrayList(map.keySet());
|
||||||
FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
|
FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ supported_version=1.16.4/5
|
|||||||
|
|
||||||
archives_base_name=architectury
|
archives_base_name=architectury
|
||||||
archives_base_name_snapshot=architectury-snapshot
|
archives_base_name_snapshot=architectury-snapshot
|
||||||
base_version=1.16
|
base_version=1.17
|
||||||
maven_group=me.shedaniel
|
maven_group=me.shedaniel
|
||||||
|
|
||||||
fabric_loader_version=0.11.1
|
fabric_loader_version=0.11.1
|
||||||
|
|||||||
@@ -20,9 +20,11 @@
|
|||||||
package me.shedaniel.architectury.test;
|
package me.shedaniel.architectury.test;
|
||||||
|
|
||||||
import me.shedaniel.architectury.platform.Platform;
|
import me.shedaniel.architectury.platform.Platform;
|
||||||
|
import me.shedaniel.architectury.registry.entity.EntityRenderers;
|
||||||
import me.shedaniel.architectury.test.debug.ConsoleMessageSink;
|
import me.shedaniel.architectury.test.debug.ConsoleMessageSink;
|
||||||
import me.shedaniel.architectury.test.debug.MessageSink;
|
import me.shedaniel.architectury.test.debug.MessageSink;
|
||||||
import me.shedaniel.architectury.test.debug.client.ClientOverlayMessageSink;
|
import me.shedaniel.architectury.test.debug.client.ClientOverlayMessageSink;
|
||||||
|
import me.shedaniel.architectury.test.entity.TestEntity;
|
||||||
import me.shedaniel.architectury.test.events.DebugEvents;
|
import me.shedaniel.architectury.test.events.DebugEvents;
|
||||||
import me.shedaniel.architectury.test.gamerule.TestGameRules;
|
import me.shedaniel.architectury.test.gamerule.TestGameRules;
|
||||||
import me.shedaniel.architectury.test.registry.TestRegistries;
|
import me.shedaniel.architectury.test.registry.TestRegistries;
|
||||||
@@ -31,6 +33,7 @@ import me.shedaniel.architectury.test.tags.TestTags;
|
|||||||
import me.shedaniel.architectury.test.trade.TestTrades;
|
import me.shedaniel.architectury.test.trade.TestTrades;
|
||||||
import me.shedaniel.architectury.utils.Env;
|
import me.shedaniel.architectury.utils.Env;
|
||||||
import me.shedaniel.architectury.utils.EnvExecutor;
|
import me.shedaniel.architectury.utils.EnvExecutor;
|
||||||
|
import net.minecraft.client.renderer.entity.MinecartRenderer;
|
||||||
|
|
||||||
public class TestMod {
|
public class TestMod {
|
||||||
public static final MessageSink SINK = EnvExecutor.getEnvSpecific(() -> ClientOverlayMessageSink::new, () -> ConsoleMessageSink::new);
|
public static final MessageSink SINK = EnvExecutor.getEnvSpecific(() -> ClientOverlayMessageSink::new, () -> ConsoleMessageSink::new);
|
||||||
@@ -42,7 +45,9 @@ public class TestMod {
|
|||||||
TestGameRules.init();
|
TestGameRules.init();
|
||||||
TestTags.initialize();
|
TestTags.initialize();
|
||||||
TestTrades.init();
|
TestTrades.init();
|
||||||
if (Platform.getEnvironment() == Env.CLIENT)
|
if (Platform.getEnvironment() == Env.CLIENT) {
|
||||||
TestKeybinds.initialize();
|
TestKeybinds.initialize();
|
||||||
|
EntityRenderers.register(TestEntity.TYPE, MinecartRenderer<TestEntity>::new);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of architectury.
|
||||||
|
* Copyright (C) 2020, 2021 architectury
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.shedaniel.architectury.test.entity;
|
||||||
|
|
||||||
|
import me.shedaniel.architectury.networking.NetworkManager;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.MobCategory;
|
||||||
|
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public class TestEntity extends AbstractMinecart {
|
||||||
|
public static final EntityType<TestEntity> TYPE = EntityType.Builder.of(TestEntity::new, MobCategory.MISC).sized(0.98F, 0.7F).clientTrackingRange(8).build("test_entity");
|
||||||
|
|
||||||
|
public TestEntity(EntityType<? extends AbstractMinecart> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getMinecartType() {
|
||||||
|
return Type.RIDEABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet<?> getAddEntityPacket() {
|
||||||
|
return NetworkManager.createAddEntityPacket(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,10 +24,12 @@ import me.shedaniel.architectury.registry.BlockProperties;
|
|||||||
import me.shedaniel.architectury.registry.DeferredRegister;
|
import me.shedaniel.architectury.registry.DeferredRegister;
|
||||||
import me.shedaniel.architectury.registry.RegistrySupplier;
|
import me.shedaniel.architectury.registry.RegistrySupplier;
|
||||||
import me.shedaniel.architectury.test.TestMod;
|
import me.shedaniel.architectury.test.TestMod;
|
||||||
|
import me.shedaniel.architectury.test.entity.TestEntity;
|
||||||
import me.shedaniel.architectury.test.registry.objects.EquippableTickingItem;
|
import me.shedaniel.architectury.test.registry.objects.EquippableTickingItem;
|
||||||
import me.shedaniel.architectury.test.tab.TestCreativeTabs;
|
import me.shedaniel.architectury.test.tab.TestCreativeTabs;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.item.BlockItem;
|
import net.minecraft.world.item.BlockItem;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
@@ -42,6 +44,7 @@ import static me.shedaniel.architectury.test.TestMod.SINK;
|
|||||||
public class TestRegistries {
|
public class TestRegistries {
|
||||||
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(TestMod.MOD_ID, Registry.ITEM_REGISTRY);
|
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(TestMod.MOD_ID, Registry.ITEM_REGISTRY);
|
||||||
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(TestMod.MOD_ID, Registry.BLOCK_REGISTRY);
|
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(TestMod.MOD_ID, Registry.BLOCK_REGISTRY);
|
||||||
|
public static final DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(TestMod.MOD_ID, Registry.ENTITY_TYPE_REGISTRY);
|
||||||
|
|
||||||
public static final RegistrySupplier<Item> TEST_ITEM = ITEMS.register("test_item", () ->
|
public static final RegistrySupplier<Item> TEST_ITEM = ITEMS.register("test_item", () ->
|
||||||
new Item(new Item.Properties().tab(TestCreativeTabs.TEST_TAB)));
|
new Item(new Item.Properties().tab(TestCreativeTabs.TEST_TAB)));
|
||||||
@@ -64,8 +67,11 @@ public class TestRegistries {
|
|||||||
public static final RegistrySupplier<Item> COLLISION_BLOCK_ITEM = ITEMS.register("collision_block", () ->
|
public static final RegistrySupplier<Item> COLLISION_BLOCK_ITEM = ITEMS.register("collision_block", () ->
|
||||||
new BlockItem(COLLISION_BLOCK.get(), new Item.Properties().tab(TestCreativeTabs.TEST_TAB)));
|
new BlockItem(COLLISION_BLOCK.get(), new Item.Properties().tab(TestCreativeTabs.TEST_TAB)));
|
||||||
|
|
||||||
|
public static final RegistrySupplier<EntityType<TestEntity>> TEST_ENTITY = ENTITY_TYPES.register("test_entity", () -> TestEntity.TYPE);
|
||||||
|
|
||||||
public static void initialize() {
|
public static void initialize() {
|
||||||
BLOCKS.register();
|
BLOCKS.register();
|
||||||
ITEMS.register();
|
ITEMS.register();
|
||||||
|
ENTITY_TYPES.register();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user