User Tools

Site Tools


tutorial:projectiles

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
tutorial:projectiles [2022/04/29 03:38]
ayutac updated a method call
tutorial:projectiles [2022/09/29 14:37] (current)
patrickmsm Remove spawn packet code, since createSpawnPacket is already overriden by ProjectileEntity.
Line 10: Line 10:
 We will be creating a custom snowball-like projectile that applies some very nasty effects to the entity that has been hit. We will be creating a custom snowball-like projectile that applies some very nasty effects to the entity that has been hit.
  
-// If you would like to look over the source code yourself, all of the following code was done [[https://​github.com/​spxctreofficial/​fabric-projectile-tutorial|here]]. Before the tutorial begins, I would like to let you know that I would be using PascalCase to name the methods. Feel free to change the naming scheme to however you like, but I personally swear by PascalCase. //+// If you would like to look over the source code yourself, all of the following code was done [[https://​github.com/​spxctreofficial/​fabric-projectile-tutorial|here]]. Before the tutorial begins, I would like to let you know that I would be using PascalCase to name the methods. Feel free to change the naming scheme to however you like, but I personally swear by PascalCase. ​Note that this may be outdated ​//
  
 ===== Creating & Registering a Projectile Entity ===== ===== Creating & Registering a Projectile Entity =====
Line 83: Line 83:
  return null; // We will configure this later, once we have created the ProjectileItem.  return null; // We will configure this later, once we have created the ProjectileItem.
  }  }
 + @Override
  
  @Environment(EnvType.CLIENT)  @Environment(EnvType.CLIENT)
Line 249: Line 250:
 ===== Rendering your Projectile Entity ===== ===== Rendering your Projectile Entity =====
  
-Your projectile entity is now defined and registered, but we are not done. Without a renderer, the ''​ProjectileEntity''​ will crash Minecraft. To fix this, we will define and register the ''​EntityRenderer''​ for our ''​ProjectileEntity''​. To do this, we will need a ''​EntityRenderer''​ in the **ClientModInitializer** ​and a spawn packet to make sure the texture is rendered correctly. +Your projectile entity is now defined and registered, but we are not done. Without a renderer, the ''​ProjectileEntity''​ will crash Minecraft. To fix this, we will define and register the ''​EntityRenderer''​ for our ''​ProjectileEntity''​. To do this, we will need a ''​EntityRenderer''​ in the **ClientModInitializer**. Go into your **ClientModInitializer** and write the following:
-\\ +
-Before we start, we will quickly define an Identifier that we will be using a lot: our PacketID. +
-<code java> +
-public static final Identifier PacketID = new Identifier(ProjectileTutorialMod.ModID,​ "​spawn_packet"​);​ +
-</​code>​ +
-\\ +
-First on the list, we should get the ''​EntityRenderer''​ out of the way. Go into your **ClientModInitializer** and write the following:+
 <code java [enable_line_numbers="​true"​]>​ <code java [enable_line_numbers="​true"​]>​
  @Override  @Override
Line 266: Line 260:
  new FlyingItemEntityRenderer(context));​ */  new FlyingItemEntityRenderer(context));​ */
  [. . .]  [. . .]
- } 
-</​code>​ 
- 
-In order for the projectileEntity to be registered, we will need a spawn packet. Create a new class named ''​EntitySpawnPacket'',​ and put this in that class. 
-<code java [enable_line_numbers="​true"​]>​ 
-public class EntitySpawnPacket { 
- public static Packet<?>​ create(Entity e, Identifier packetID) { 
- if (e.world.isClient) 
- throw new IllegalStateException("​SpawnPacketUtil.create called on the logical client!"​);​ 
- PacketByteBuf byteBuf = new PacketByteBuf(Unpooled.buffer());​ 
- byteBuf.writeVarInt(Registry.ENTITY_TYPE.getRawId(e.getType()));​ 
- byteBuf.writeUuid(e.getUuid());​ 
- byteBuf.writeVarInt(e.getEntityId());​ 
-                ​ 
- PacketBufUtil.writeVec3d(byteBuf,​ e.getPos());​ 
- PacketBufUtil.writeAngle(byteBuf,​ e.pitch); 
- PacketBufUtil.writeAngle(byteBuf,​ e.yaw); 
-                /* 
-                In 1.17,we use these. 
-                byteBuf.writeVarInt(e.getId());​ 
-                ​ 
-                PacketBufUtil.writeVec3d(byteBuf,​ e.getPos());​ 
-                PacketBufUtil.writeAngle(byteBuf,​ e.getPitch());​ 
-                PacketBufUtil.writeAngle(byteBuf,​ e.getYaw()); ​             ​ 
-                */ 
- 
- return ServerPlayNetworking.createS2CPacket(packetID,​ byteBuf); 
- } 
- public static final class PacketBufUtil { 
- 
- /** 
- * Packs a floating-point angle into a {@code byte}. 
- * 
- * @param angle 
- *         angle 
- * @return packed angle 
- */ 
- public static byte packAngle(float angle) { 
- return (byte) MathHelper.floor(angle * 256 / 360); 
- } 
- 
- /** 
- * Unpacks a floating-point angle from a {@code byte}. 
- * 
- * @param angleByte 
- *         ​packed angle 
- * @return angle 
- */ 
- public static float unpackAngle(byte angleByte) { 
- return (angleByte * 360) / 256f; 
- } 
- 
- /** 
- * Writes an angle to a {@link PacketByteBuf}. 
- * 
- * @param byteBuf 
- *         ​destination buffer 
- * @param angle 
- *         angle 
- */ 
- public static void writeAngle(PacketByteBuf byteBuf, float angle) { 
- byteBuf.writeByte(packAngle(angle));​ 
- } 
- 
- /** 
- * Reads an angle from a {@link PacketByteBuf}. 
- * 
- * @param byteBuf 
- *         ​source buffer 
- * @return angle 
- */ 
- public static float readAngle(PacketByteBuf byteBuf) { 
- return unpackAngle(byteBuf.readByte());​ 
- } 
- 
- /** 
- * Writes a {@link Vec3d} to a {@link PacketByteBuf}. 
- * 
- * @param byteBuf 
- *         ​destination buffer 
- * @param vec3d 
- *         ​vector 
- */ 
- public static void writeVec3d(PacketByteBuf byteBuf, Vec3d vec3d) { 
- byteBuf.writeDouble(vec3d.x);​ 
- byteBuf.writeDouble(vec3d.y);​ 
- byteBuf.writeDouble(vec3d.z);​ 
- } 
- 
- /** 
- * Reads a {@link Vec3d} from a {@link PacketByteBuf}. 
- * 
- * @param byteBuf 
- *         ​source buffer 
- * @return vector 
- */ 
- public static Vec3d readVec3d(PacketByteBuf byteBuf) { 
- double x = byteBuf.readDouble();​ 
- double y = byteBuf.readDouble();​ 
- double z = byteBuf.readDouble();​ 
- return new Vec3d(x, y, z); 
- } 
- } 
-} 
-</​code>​ 
- 
-This will basically read and write vectors and angles that will allow the entity'​s texture to be rendered correctly. I will not go in-depth about spawn packets here, but you could read up on what they do and how they function. For now, we can include this and move on. 
-\\ 
-Back to our **ClientModInitializer**,​ we will create a new method and put the following in that method. 
- 
-<code java [enable_line_numbers="​true"​]>​ 
- public void receiveEntityPacket() { 
- ClientSidePacketRegistry.INSTANCE.register(PacketID,​ (ctx, byteBuf) -> { 
- EntityType<?>​ et = Registry.ENTITY_TYPE.get(byteBuf.readVarInt());​ 
- UUID uuid = byteBuf.readUuid();​ 
- int entityId = byteBuf.readVarInt();​ 
- Vec3d pos = EntitySpawnPacket.PacketBufUtil.readVec3d(byteBuf);​ 
- float pitch = EntitySpawnPacket.PacketBufUtil.readAngle(byteBuf);​ 
- float yaw = EntitySpawnPacket.PacketBufUtil.readAngle(byteBuf);​ 
- ctx.getTaskQueue().execute(() -> { 
- if (MinecraftClient.getInstance().world == null) 
- throw new IllegalStateException("​Tried to spawn entity in a null world!"​);​ 
- Entity e = et.create(MinecraftClient.getInstance().world);​ 
- if (e == null) 
- throw new IllegalStateException("​Failed to create instance of entity \""​ + Registry.ENTITY_TYPE.getId(et) + "​\"​!"​);​ 
- e.updateTrackedPosition(pos);​ 
- e.setPos(pos.x,​ pos.y, pos.z); 
- e.pitch = pitch; 
- e.yaw = yaw; 
- e.setEntityId(entityId);​ 
- e.setUuid(uuid);​ 
- MinecraftClient.getInstance().world.addEntity(entityId,​ e); 
- }); 
- }); 
- } 
-</​code>​ 
- 
-Back in our ''​ProjectileEntity''​ class, we must add a method to make sure everything works correctly. 
-<code java [enable_line_numbers="​true"​]>​ 
-        @Override 
- public Packet createSpawnPacket() { 
- return EntitySpawnPacket.create(this,​ ProjectileTutorialClient.PacketID);​ 
- } 
-</​code>​ 
- 
-Finally, make sure to call this method in the **onInitializeClient()** method. 
- 
-<code java [enable_line_numbers="​true"​]>​ 
-@Override 
- public void onInitializeClient() { 
- EntityRendererRegistry.INSTANCE.register(ProjectileTutorialMod.PackedSnowballEntityType,​ (context) -> 
- new FlyingItemEntityRenderer(context));​ 
- receiveEntityPacket();​ 
  }  }
 </​code>​ </​code>​
tutorial/projectiles.txt · Last modified: 2022/09/29 14:37 by patrickmsm