Jump to content

LeeCrafts

Members
  • Posts

    86
  • Joined

  • Last visited

Everything posted by LeeCrafts

  1. Good golly gee I'm dense. I put the is_projectile.json file in the wrong path. It was supposed to be /resources/data/minecraft/tags/damage_type/is_projectile.json, not /resources/data/thingamabobs/tags/damage_type/is_projectile.json! That being said, I do NOT need the bootstrap method in ModDamageTypes.java, and ModDataGenerationHandler.java at all; "runData" does not need to be run either. I had already done the datagen manually.
  2. I do believe your custom mob needs to implement the RangeAttackMob interface. Then make your mob shoot 3 arrows via implementing the performRangedAttack() method. See the AbstractSkeleton class for reference, which makes the Skeleton mobs shoot only 1 arrow. If you need help on making a mob in general, refer to this video: https://www.youtube.com/watch?v=6ycbDR4hAkI
  3. While I cannot pinpoint what is preventing the rooster from damaging the player, try using a debugger and set a breakpoint in the MeleeAttackGoal class--in the tick() and/or checkAndPerformAttack() methods.
  4. Subscribe to EntityJoinLevelEvent and check if that entity is a wandering trader.
  5. I have successfully created a new damage source "bullet". But now I would like to add the damage type tag "is_projectile" to it. Even though I added the file /resources/data/thingamabobs/tags/damage_type/is_projectile.json with the appropriate JSON content, the game still does not seem to register the damage source as a projectile. So I was wondering if I needed to also register it through a bootstrap method--and call that method using an event handler: public interface ModDamageTypes { ResourceKey<DamageType> BULLET = register("bullet"); private static ResourceKey<DamageType> register(String name) { return ResourceKey.create(Registries.DAMAGE_TYPE, new ResourceLocation(ThingamabobsAndDoohickeys.MODID, name)); } // bootstrap method static void bootstrap(BootstapContext<DamageType> bootstapContext) { bootstapContext.register(BULLET, new DamageType("bullet", 0.1f)); } } @Mod.EventBusSubscriber(modid = ThingamabobsAndDoohickeys.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class ModDataGenerationHandler { private static final RegistrySetBuilder BUILDER = new RegistrySetBuilder().add(Registries.DAMAGE_TYPE, ModDamageTypes::bootstrap); @SubscribeEvent public static void gatherDataEvent(GatherDataEvent event) { DataGenerator dataGenerator = event.getGenerator(); PackOutput packOutput = dataGenerator.getPackOutput(); dataGenerator.addProvider(event.includeServer(), new DatapackBuiltinEntriesProvider( packOutput, event.getLookupProvider(), BUILDER, Set.of(ThingamabobsAndDoohickeys.MODID))); } } Unfortunately, the GatherDataEvent does not seem to fire. I heard that I had to run "runData", but the process fails, outputting the log below: What could I be missing? BTW, I was using this post for guidance: https://forums.minecraftforge.net/topic/122311-1194-how-to-create-custom-damagesources/ The rest of my code + JSON files:
  6. I would like to modify the death message for a custom weapon I implemented (e.g. "X was squashed into a pancake by Y" instead of "X was slain by Y"). Is it required that I create a new DamageSource? If not, what else can I do? Edit: The answers in the post below really helped me.
  7. Wow, I didn't know that I had to do that, thank you! This is my code, if any of you are curious: // getter and setter methods that i already had public boolean isSomething() { return this.entityData.get(DATA_IS_SOMETHING); } public void setSomething(boolean isSomething) { this.entityData.set(DATA_IS_SOMETHING, isSomething); } ... // what solved my issue @Override public void addAdditionalSaveData(@NotNull CompoundTag pCompound) { super.addAdditionalSaveData(pCompound); pCompound.putBoolean("IsSomething", this.isSomething()); } @Override public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { super.readAdditionalSaveData(pCompound); this.setSomething(pCompound.getBoolean("IsSomething")); }
  8. I am implementing a custom entity, and so far I had to add synched entity data to it. For example: private static final EntityDataAccessor<Boolean> DATA_IS_SOMETHING = SynchedEntityData.defineId(CustomEntity.class, EntityDataSerializers.BOOLEAN); @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_IS_SOMETHING, false); } Under certain conditions, the DATA_IS_SOMETHING of my entity will change to true. To my dismay though, when the player dies and then respawns, that entity's DATA_IS_SOMETHING resets back to false. Is this normal behavior? If so, then should I use capabilities instead? FYI I need the data to be synced between the server and client.
  9. This is a very specific problem, but let me elaborate: I am implementing a custom GeckoLib entity that is a sticky bomb. When thrown at another entity, the bomb must latch onto that entity by "riding" it. I need to do mainly two things in order to make the bomb really look like it is sticking to an entity: 1. Modify the bomb's riding position by overriding its Entity#setPos method. The bomb must be positioned so that it will appear stuck to the body part of the entity that it hit. 2. Modify the bomb's rotation by overriding its Projectile#updateRotation method. The bomb should be rotated so that it constantly faces its victim (i.e. the center of the victim's hitbox). The math and logic behind implementing #1 and #2 was not that difficult for me, and I was able to implement #1 successfully. However, I am struggling with #2 because whenever the vehicle itself rotates, the bomb seems to rotate the wrong way. I even tried modifying the overridden updateRotation method so that the bomb's rotation is not changed when it is riding a vehicle (i.e. this.getVehicle() != null), but the bomb somehow still rotates when the vehicle rotates. So far, I could not find any other code that modifies the rotation of a passenger entity on a vehicle. But what I have found out is that--when the bomb rotates unexpectedly--its hitbox does not rotate with it (Hitbox rotation is indicated by the direction its blue line is pointing when the player presses F3 + B). Was it being rotated clientside? What could be causing this behavior?
  10. Can you please clarify? Would this "hidden_item" be a copy of my offhand item--and, when I delete the offhand item after some time, the "hidden_item" would be placed in a free (non-offhand) slot in my inventory? If so, I have tried that and it did not work; explanation is in my code.
  11. I want to prevent the player from holding an item in the offhand slot if the player is holding a certain item in the main hand slot. My approach so far is moving the offhand ItemStack to a free slot in the inventory. As you can see, my code is based off of Inventory#placeItemBackInInventory (if I use this method directly, the offhand item would simply stay in the same slot). My implementation works...only to an extent. It sometimes does not work when I open the inventory GUI and press F on an ItemStack to move it to the offhand slot; the ItemStack appears to stay in place and not move. What exactly am I missing? I am aware this is an issue regarding networking, but I was hoping the vanilla ClientboundContainerSetSlotPacket would prevent that. // DISREGARD THIS WHOLE BLOCK OF CODE @SubscribeEvent public static void holdingCustomItemTick(TickEvent.PlayerTickEvent event) { if (event.phase == TickEvent.Phase.END) { if (event.player instanceof ServerPlayer serverPlayer && serverPlayer.tickCount % 20 == 0) { // I may remove the % 20 == 0 part later ItemStack offhandItem = serverPlayer.getOffhandItem(); if (serverPlayer.getMainHandItem().getItem() == ModItems.CUSTOM_ITEM.get() && !offhandItem.isEmpty()) { // I previously tried using just these 3 lines, but it did not work (which makes sense because ItemStack#shrink and Player#addItem do not send packets to the client) // ItemStack offhandItem1 = offhandItem.copy(); // offhandItem.shrink(offhandItem.getCount()); // serverPlayer.addItem(offhandItem1); Inventory inventory = serverPlayer.getInventory(); int i = inventory.getFreeSlot(); if (i != -1) { int j = offhandItem.getMaxStackSize() - inventory.getItem(i).getCount(); if (inventory.add(i, offhandItem.split(j))) { serverPlayer.connection.send( new ClientboundContainerSetSlotPacket(-2, 0, i, inventory.getItem(i))); } } else { inventory.player.drop(offhandItem, false); } } } } } EDIT as of 11/23/2023: Disregard everything above this. After giving up and then coming back a few months later, I finally found a solution! It only works in survival, but that's fine with me // When the (non-creative) player is holding the item on their main hand, they are not allowed to equip any item in the offhand. @SubscribeEvent public static void livingEquipmentChangeEvent(LivingEquipmentChangeEvent event) { if (event.getEntity() instanceof Player player && !player.isCreative() && !player.level.isClientSide && player.getMainHandItem().getItem() == ModItems.CUSTOM_ITEM.get()) { ItemStack offhandItem = player.getOffhandItem(); if (!offhandItem.isEmpty()) { ItemEntity itemEntity = player.drop(offhandItem.copy(), true); offhandItem.shrink(offhandItem.getCount()); if (itemEntity != null) { itemEntity.setPickUpDelay(0); } } } }
  12. I would like to force the pose of a living entity to a standing position (i.e. Pose.STANDING) when it is riding a certain vehicle. I have tried to call Entity#setPose every tick via LivingTickEvent, but the living entity remains in a sitting position. Here is my code: // I made it a low-priority event because I was wondering if the code should be executed at the end of each tick. @SubscribeEvent(priority = EventPriority.LOWEST) public static void livingTickEvent(LivingEvent.LivingTickEvent event) { LivingEntity livingEntity = event.getEntity(); if (!livingEntity.level.isClientSide && livingEntity.getVehicle() instanceof TheVehicle) { livingEntity.setPose(Pose.STANDING); } } By the way, I am aware there is a setForcedPose method, but it's only for the Player class.
  13. Thank you! Here is my overridden method: @Override public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { return enchantment == Enchantments.SILK_TOUCH || super.canApplyAtEnchantingTable(stack, enchantment); }
  14. I have a weapon that extends CrossbowItem. I made its projectiles able to destroy certain blocks, but I wonder if I can make the weapon compatible with the Silk Touch enchantment--so that those destroyed blocks can drop themselves. (Of course I would have to code the logic myself after checking if the weapon has the enchantment.) How do I do this? It seems like Silk Touch is of the "DIGGER" category, and only items extending DiggerItem (aka not my weapon) are naturally compatible with that enchantment.
  15. As seen in the CrossbowItem class, an NBT boolean tag “Charged” is attached to crossbows. I have a custom item that extends CrossbowItem, and I want to attach other data in addition to the “Charged” tag. Should I use capabilities or NBTs? I am wondering if there are any significant advantages of using one over another for ItemStacks.
  16. I would like to create player animations upon holding and attacking with an item. Specifically, I want the player to move its body and both arms while using the weapon (in the third-person view). Currently, I am playing around with IClientItemExtensions (https://forge.gemwire.uk/wiki/Custom_Item_Animations), but I do not see a way to move the player's body using this method. Would I have to use an animation engine like Geckolib? Edit: My solution was to use an external animation library, as suggested by @Ninjaguy169. I used KosmX's PlayerAnimator (https://github.com/KosmX/minecraftPlayerAnimator), and it was helpful to look through the library's Discord server and GitHub.
  17. My solution is in the code below. Please let me know if there is a better way. // client events @Mod.EventBusSubscriber(modid = ExampleMod.MODID, value = Dist.CLIENT) public static class ClientForgeEvents { // To attack with the hammer, the player must hold left click for CHARGE_LIMIT ticks, and then let go. // A capability is attached to LocalPlayers to store the hammer charge time. // Uncomment the commented lines if you want the attack indicator bar to fill while the hammer attack is charged. // However, you would need access transformers for this. It becomes even more necessary to modify the LivingEntity::attackStrengthTicker field when the packet is sent to the server (see the packet class below). @SubscribeEvent public static void clientTick(TickEvent.ClientTickEvent event) { if (event.phase == TickEvent.Phase.END) { LocalPlayer localPlayer = Minecraft.getInstance().player; if (localPlayer != null) { localPlayer.getCapability(ModCapabilities.PLAYER_CAPABILITY).ifPresent(iPlayerCap -> { PlayerCap playerCap = (PlayerCap) iPlayerCap; boolean leftMouse = Minecraft.getInstance().mouseHandler.isLeftPressed(); boolean holdingHammer = localPlayer.getMainHandItem().getItem() == ModItems.HAMMER_THING.get(); if (!holdingHammer || !leftMouse) { if (!leftMouse) { if (playerCap.hammerCharge >= CHARGE_LIMIT) { localPlayer.swing(InteractionHand.MAIN_HAND); // If an entity is in reach, it'll be hit by the hammer attack (see packet class below) HitResult hitResult = Minecraft.getInstance().hitResult; if (hitResult != null && hitResult.getType() == HitResult.Type.ENTITY) { int entityId = ((EntityHitResult) hitResult).getEntity().getId(); PacketHandler.INSTANCE.sendToServer(new ServerboundHammerThingAttackPacket(entityId)); } } } playerCap.hammerCharge = 0; // if (holdingHammer) localPlayer.attackStrengthTicker = CHARGE_LIMIT; } else { playerCap.hammerCharge = Math.min(CHARGE_LIMIT, playerCap.hammerCharge + 1); // localPlayer.attackStrengthTicker = playerCap.hammerCharge; } }); } } } // cancels vanilla mining and swinging mechanics when player presses left click while holding hammer @SubscribeEvent public static void inputEvent(InputEvent.InteractionKeyMappingTriggered event) { if (event.isAttack()) { LocalPlayer localPlayer = Minecraft.getInstance().player; if (localPlayer != null && localPlayer.getMainHandItem().getItem() == ModItems.HAMMER_THING.get()) { event.setSwingHand(false); event.setCanceled(true); } } } } // packet class public class ServerboundHammerThingAttackPacket { public final int targetId; public ServerboundHammerThingAttackPacket(int targetId) { this.targetId = targetId; } public ServerboundHammerThingAttackPacket(FriendlyByteBuf buffer) { this(buffer.readInt()); } public void encode(FriendlyByteBuf buffer) { buffer.writeInt(this.targetId); } public void handle(Supplier<NetworkEvent.Context> ctx) { ctx.get().enqueueWork(() -> { ServerPlayer sender = ctx.get().getSender(); if (sender != null) { // This line is necessary. Otherwise attackStrengthTicker would be 0, making the attack very weak. // attackStrengthTicker must be set server side, hence the server bound packet. sender.attackStrengthTicker = CHARGE_LIMIT; Entity entity = sender.level.getEntity(this.targetId); if (entity != null) { sender.attack(entity); } } }); ctx.get().setPacketHandled(true); } } // and finally, the packet handler class public class PacketHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel( new ResourceLocation(ExampleMod.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); private PacketHandler() { } public static void init() { int index = 0; INSTANCE.messageBuilder(ServerboundHammerThingAttackPacket.class, index++, NetworkDirection.PLAY_TO_SERVER) .encoder(ServerboundHammerThingAttackPacket::encode).decoder(ServerboundHammerThingAttackPacket::new) .consumerMainThread(ServerboundHammerThingAttackPacket::handle).add(); } } (btw if you think the (first person) item animations are a bit awkward, I recommend you to look at this: https://forge.gemwire.uk/wiki/Custom_Item_Animations)
  18. Yes, true. That's the challenge I believe. The weapon I'm trying to make is supposed to be heavy hammer, and I would think it would be a bit unfitting if I had to use right-click to attack with a melee weapon.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.