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 revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
tutorial:projectiles [2022/02/10 15:08] – [Rendering your Projectile Entity] tianjuntutorial:projectiles [2022/09/29 14:37] – Remove spawn packet code, since createSpawnPacket is already overriden by ProjectileEntity. patrickmsm
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
  public void onInitializeClient() {  public void onInitializeClient() {
- EntityRendererRegistry.INSTANCE.register(ProjectileTutorialMod.PackedSnowballEntityType, (context) ->+ EntityRendererRegistry.register(ProjectileTutorialMod.PackedSnowballEntityType, (context) ->
  new FlyingItemEntityRenderer(context));  new FlyingItemEntityRenderer(context));
 + // older versions may have to use
 + /* EntityRendererRegistry.INSTANCE.register(ProjectileTutorialMod.PackedSnowballEntityType, (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: 2024/03/08 01:56 by netuserget