From d62351e2f0575108c0de49783e02f43adf1e444d Mon Sep 17 00:00:00 2001 From: ElsaCounteragent Date: Tue, 28 Apr 2026 11:36:03 +0300 Subject: [PATCH 1/2] Added a bunch of new stuff --- .../playercollars/client/LaserRenderer.java | 4 ++++ .../playercollars/item/GroomingBrushItem.java | 4 ++++ .../playercollars/item/LaserPointerItem.java | 4 ++++ .../playercollars/item/RewardTreatPouchItem.java | 4 ++++ .../playercollars/items/grooming_brush.json | 0 .../assets/playercollars/items/laser_pointer.json | 0 .../playercollars/models/item/grooming_brush.json | 6 ++++++ .../playercollars/models/item/laser_pointer.json | 6 ++++++ .../textures/item/grooming_brush.png | Bin 0 -> 312 bytes .../playercollars/textures/item/laser_pointer.png | Bin 0 -> 270 bytes .../playercollars/enchantment/laser_reach.json | 0 11 files changed, 28 insertions(+) create mode 100644 src/main/java/org/jlortiz/playercollars/client/LaserRenderer.java create mode 100644 src/main/java/org/jlortiz/playercollars/item/GroomingBrushItem.java create mode 100644 src/main/java/org/jlortiz/playercollars/item/LaserPointerItem.java create mode 100644 src/main/java/org/jlortiz/playercollars/item/RewardTreatPouchItem.java create mode 100644 src/main/resources/assets/playercollars/items/grooming_brush.json create mode 100644 src/main/resources/assets/playercollars/items/laser_pointer.json create mode 100644 src/main/resources/assets/playercollars/models/item/grooming_brush.json create mode 100644 src/main/resources/assets/playercollars/models/item/laser_pointer.json create mode 100644 src/main/resources/assets/playercollars/textures/item/grooming_brush.png create mode 100644 src/main/resources/assets/playercollars/textures/item/laser_pointer.png create mode 100644 src/main/resources/data/playercollars/enchantment/laser_reach.json diff --git a/src/main/java/org/jlortiz/playercollars/client/LaserRenderer.java b/src/main/java/org/jlortiz/playercollars/client/LaserRenderer.java new file mode 100644 index 00000000..c9004040 --- /dev/null +++ b/src/main/java/org/jlortiz/playercollars/client/LaserRenderer.java @@ -0,0 +1,4 @@ +package org.jlortiz.playercollars.client; + +public class LaserRenderer { +} diff --git a/src/main/java/org/jlortiz/playercollars/item/GroomingBrushItem.java b/src/main/java/org/jlortiz/playercollars/item/GroomingBrushItem.java new file mode 100644 index 00000000..380c5b38 --- /dev/null +++ b/src/main/java/org/jlortiz/playercollars/item/GroomingBrushItem.java @@ -0,0 +1,4 @@ +package org.jlortiz.playercollars.item; + +public class BrushItem { +} diff --git a/src/main/java/org/jlortiz/playercollars/item/LaserPointerItem.java b/src/main/java/org/jlortiz/playercollars/item/LaserPointerItem.java new file mode 100644 index 00000000..e8fc0b12 --- /dev/null +++ b/src/main/java/org/jlortiz/playercollars/item/LaserPointerItem.java @@ -0,0 +1,4 @@ +package org.jlortiz.playercollars.item; + +public class LaserPointerItem { +} diff --git a/src/main/java/org/jlortiz/playercollars/item/RewardTreatPouchItem.java b/src/main/java/org/jlortiz/playercollars/item/RewardTreatPouchItem.java new file mode 100644 index 00000000..bcf3a92e --- /dev/null +++ b/src/main/java/org/jlortiz/playercollars/item/RewardTreatPouchItem.java @@ -0,0 +1,4 @@ +package org.jlortiz.playercollars.item; + +public class RewardTreatPouchItem { +} diff --git a/src/main/resources/assets/playercollars/items/grooming_brush.json b/src/main/resources/assets/playercollars/items/grooming_brush.json new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/assets/playercollars/items/laser_pointer.json b/src/main/resources/assets/playercollars/items/laser_pointer.json new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/assets/playercollars/models/item/grooming_brush.json b/src/main/resources/assets/playercollars/models/item/grooming_brush.json new file mode 100644 index 00000000..4f02baab --- /dev/null +++ b/src/main/resources/assets/playercollars/models/item/grooming_brush.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "playercollars:item/grooming_brush" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/playercollars/models/item/laser_pointer.json b/src/main/resources/assets/playercollars/models/item/laser_pointer.json new file mode 100644 index 00000000..f80e4f85 --- /dev/null +++ b/src/main/resources/assets/playercollars/models/item/laser_pointer.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "playercollars:item/laser_pointer" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/playercollars/textures/item/grooming_brush.png b/src/main/resources/assets/playercollars/textures/item/grooming_brush.png new file mode 100644 index 0000000000000000000000000000000000000000..d00ba589bd65513b32029fbfd3ac0784db7ff987 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8K8Aw(>tdav#iUB?$u0VS0(v=e%TOZ!Ib@%42 zqNHR?ece!3r_Ml~brmt!m$gnWPOAngVk`;r3ubV5b|VeQIqK=+7*cWT?KMZLf67M;u_%@~pn$E#-FT>-*~Edfxk@Hy@3kyXnM>Ifd2&A|h|ZoMiV$ zH8nN)teD>OI3ysTAU}3<+F3SM*45G1#Mb!=J32akTNRmmNQ#Y%Yg&N9<@{_34ULNP zT{ojdB)2O&I3C<2C#ltcC2nbRb5m19%cyfCh`6$!?W0VG|KK zlC}Plb#_7sP)tWg>smxWzyzs?L{2U)p{#TkR#y9+KNfP%veS4E^bmumtDnm{r-UW| D`QCD7 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/playercollars/textures/item/laser_pointer.png b/src/main/resources/assets/playercollars/textures/item/laser_pointer.png new file mode 100644 index 0000000000000000000000000000000000000000..6f06544c862c3f5229c6346bee9f6249c3cecf26 GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP;i!~ zi(`mI@7oKCe9aCbEf4>ju8i2e$k%||v50Yk?+&IeTjA>u6xP166cBx}O08LQUTomi zkM~oICd{Z?Hp#_4c&bxmgwWCnQ=Uy^$;v%`RMuN-#p|f00$JyOPr4jv!_z#cc+YzA zuH&DX6Vi@zIdMcyYh9KZas6tXc}iJ9Er;V}latl+f7}p1F7f|IdWFpKnmeVja%>;& zJx@+xzNMAS+Q(rW2XrNar>mdKI;Vstfm=4l7ME-;->bfw)?;`)ks;oqq;R9(i>DpP FssKigW?KLN literal 0 HcmV?d00001 diff --git a/src/main/resources/data/playercollars/enchantment/laser_reach.json b/src/main/resources/data/playercollars/enchantment/laser_reach.json new file mode 100644 index 00000000..e69de29b From 419e2ecffefbe9433d0c82c40519e41fea621085 Mon Sep 17 00:00:00 2001 From: ElsaCounteragent Date: Tue, 28 Apr 2026 11:55:07 +0300 Subject: [PATCH 2/2] Added a bunch of new stuff yay --- .../assets/playercollars/lang/en_us.json | 6 +- .../recipes/tools/grooming_brush.json | 32 ++++++ .../recipes/tools/laser_pointer.json | 32 ++++++ .../playercollars/recipe/grooming_brush.json | 17 ++++ .../playercollars/recipe/laser_pointer.json | 18 ++++ .../playercollars/PlayerCollarsMod.java | 93 ++++++++++++++++++ .../playercollars/block/DogBowlBlock.java | 18 +++- .../block/InvisibleFenceBlock.java | 25 ++++- .../playercollars/client/LaserRenderer.java | 92 ++++++++++++++++- .../playercollars/client/RegisterClient.java | 1 + .../datagen/RecipeDataGenerator.java | 17 ++++ .../playercollars/item/GroomingBrushItem.java | 35 ++++++- .../playercollars/item/LaserPointerItem.java | 77 ++++++++++++++- .../playercollars/item/PawSetupItem.java | 49 ++++++--- .../item/RewardTreatPouchItem.java | 61 +++++++++++- .../mixin/PlayerEntityMixin.java | 40 +++++--- .../playercollars/items/grooming_brush.json | 6 ++ .../playercollars/items/laser_pointer.json | 6 ++ .../playercollars/lang/en_us.existing.json | 84 +++++++++++++++- .../models/item/grooming_brush.json | 6 +- .../textures/item/laser_pointer.png | Bin 270 -> 270 bytes .../tags/enchantment/in_enchanting_table.json | 3 +- .../enchantment/laser_reach.json | 23 +++++ 23 files changed, 699 insertions(+), 42 deletions(-) create mode 100644 src/main/generated/data/playercollars/advancement/recipes/tools/grooming_brush.json create mode 100644 src/main/generated/data/playercollars/advancement/recipes/tools/laser_pointer.json create mode 100644 src/main/generated/data/playercollars/recipe/grooming_brush.json create mode 100644 src/main/generated/data/playercollars/recipe/laser_pointer.json diff --git a/src/main/generated/assets/playercollars/lang/en_us.json b/src/main/generated/assets/playercollars/lang/en_us.json index 7f131399..5f7331db 100644 --- a/src/main/generated/assets/playercollars/lang/en_us.json +++ b/src/main/generated/assets/playercollars/lang/en_us.json @@ -39,6 +39,7 @@ "block.playercollars.yellow_dog_bowl": "Yellow Dog Bowl", "enchantment.playercollars.clicker": "Audible", "enchantment.playercollars.clicker_walk": "Beckon", + "enchantment.playercollars.laser_reach": "Laser Reach", "enchantment.playercollars.regeneration": "Healing", "enchantment.playercollars.short_leash": "Tight Leash", "enchantment.playercollars.thorns": "Spiked", @@ -148,5 +149,8 @@ "message.playercollars.no_ride_entity": "Can't ride this entity!", "sound.playercollars.clicker_off": "Clicker clicks off", "sound.playercollars.clicker_on": "Clicker clicks on", - "tag.block.playercollars.paws_allow_interact": "Usable with Paws" + "tag.block.playercollars.paws_allow_interact": "Usable with Paws", + "item.playercollars.grooming_brush": "Magic Grooming Brush", + "item.playercollars.laser_pointer": "Laser Pointer", + "item.playercollars.reward_treat_pouch": "Reward Treat Pouch" } \ No newline at end of file diff --git a/src/main/generated/data/playercollars/advancement/recipes/tools/grooming_brush.json b/src/main/generated/data/playercollars/advancement/recipes/tools/grooming_brush.json new file mode 100644 index 00000000..fd8129b1 --- /dev/null +++ b/src/main/generated/data/playercollars/advancement/recipes/tools/grooming_brush.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_copper_ingot": { + "conditions": { + "items": [ + { + "items": "#c:ingots/copper" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "playercollars:grooming_brush" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_copper_ingot" + ] + ], + "rewards": { + "recipes": [ + "playercollars:grooming_brush" + ] + } +} \ No newline at end of file diff --git a/src/main/generated/data/playercollars/advancement/recipes/tools/laser_pointer.json b/src/main/generated/data/playercollars/advancement/recipes/tools/laser_pointer.json new file mode 100644 index 00000000..a876c2f5 --- /dev/null +++ b/src/main/generated/data/playercollars/advancement/recipes/tools/laser_pointer.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_emerald": { + "conditions": { + "items": [ + { + "items": "minecraft:emerald" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "playercollars:laser_pointer" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_emerald" + ] + ], + "rewards": { + "recipes": [ + "playercollars:laser_pointer" + ] + } +} \ No newline at end of file diff --git a/src/main/generated/data/playercollars/recipe/grooming_brush.json b/src/main/generated/data/playercollars/recipe/grooming_brush.json new file mode 100644 index 00000000..15afa8c1 --- /dev/null +++ b/src/main/generated/data/playercollars/recipe/grooming_brush.json @@ -0,0 +1,17 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "c": "minecraft:copper_ingot", + "d": "minecraft:white_dye", + "w": "minecraft:wheat" + }, + "pattern": [ + " wd", + " c " + ], + "result": { + "count": 1, + "id": "playercollars:grooming_brush" + } +} \ No newline at end of file diff --git a/src/main/generated/data/playercollars/recipe/laser_pointer.json b/src/main/generated/data/playercollars/recipe/laser_pointer.json new file mode 100644 index 00000000..641ffc45 --- /dev/null +++ b/src/main/generated/data/playercollars/recipe/laser_pointer.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "e": "minecraft:emerald", + "g": "minecraft:glass_pane", + "i": "#c:ingots/iron" + }, + "pattern": [ + " g ", + " e ", + " i " + ], + "result": { + "count": 1, + "id": "playercollars:laser_pointer" + } +} \ No newline at end of file diff --git a/src/main/java/org/jlortiz/playercollars/PlayerCollarsMod.java b/src/main/java/org/jlortiz/playercollars/PlayerCollarsMod.java index 851d9bf0..047c39e4 100644 --- a/src/main/java/org/jlortiz/playercollars/PlayerCollarsMod.java +++ b/src/main/java/org/jlortiz/playercollars/PlayerCollarsMod.java @@ -12,6 +12,7 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.player.AttackEntityCallback; import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; +import net.fabricmc.fabric.api.event.player.UseItemCallback; import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory; import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry; import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; @@ -22,10 +23,12 @@ import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.component.DataComponentTypes; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.piston.PistonBehavior; import net.minecraft.component.ComponentType; +import net.minecraft.component.type.FoodComponent; import net.minecraft.entity.Entity; import net.minecraft.entity.Leashable; import net.minecraft.entity.LivingEntity; @@ -37,6 +40,7 @@ import net.minecraft.item.*; import net.minecraft.network.codec.PacketCodecs; import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket; +import net.minecraft.particle.ParticleTypes; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; @@ -46,7 +50,9 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.BlockSoundGroup; +import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; import net.minecraft.util.*; import net.minecraft.util.dynamic.Codecs; @@ -69,6 +75,12 @@ import java.util.UUID; import java.util.function.UnaryOperator; +import net.fabricmc.fabric.api.event.player.UseEntityCallback; +import net.minecraft.util.ActionResult; +import net.minecraft.item.ItemStack; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.world.ServerWorld; + public class PlayerCollarsMod implements ModInitializer { public static final String MOD_ID = "playercollars"; public static final CollarItem COLLAR_ITEM = Registry.register(Registries.ITEM, CollarItem.REGISTRY_KEY, new CollarItem(false)); @@ -83,6 +95,16 @@ public class PlayerCollarsMod implements ModInitializer { public static final PawSetupItem PAW_CONFIGURATION_ITEM = Registry.register(Registries.ITEM, PawSetupItem.REGISTRY_KEY, new PawSetupItem()); public static final CollarLockerItem COLLAR_LOCKER_ITEM = Registry.register(Registries.ITEM, CollarLockerItem.REGISTRY_KEY, new CollarLockerItem()); public static final SpatulaItem SPATULA_ITEM = Registry.register(Registries.ITEM, Identifier.of(MOD_ID, "golden_spatula"), new SpatulaItem()); + public static final GroomingBrushItem GROOMING_BRUSH_ITEM = Registry.register( + Registries.ITEM, + Identifier.of(MOD_ID, "grooming_brush"), + new GroomingBrushItem(new Item.Settings().registryKey(RegistryKey.of(RegistryKeys.ITEM, Identifier.of(MOD_ID, "grooming_brush")))) + ); + public static final LaserPointerItem LASER_POINTER_ITEM = Registry.register( + Registries.ITEM, + Identifier.of(MOD_ID, "laser_pointer"), + new LaserPointerItem(new Item.Settings().maxCount(1).registryKey(RegistryKey.of(RegistryKeys.ITEM, Identifier.of(MOD_ID, "laser_pointer")))) + ); public static final SoundEvent CLICKER_ON = Registry.register(Registries.SOUND_EVENT, Identifier.of(MOD_ID, "clicker_on"), SoundEvent.of(Identifier.of(MOD_ID, "clicker_on"))); @@ -99,6 +121,19 @@ public class PlayerCollarsMod implements ModInitializer { Registries.DATA_COMPONENT_TYPE, Identifier.of(MOD_ID, "owner_component"), ComponentType.builder().codec(OWNER_COMPONENT_CODEC).build()); + public static final ComponentType FORCED_CRAWL_COMPONENT_TYPE = Registry.register( + Registries.DATA_COMPONENT_TYPE, + Identifier.of(MOD_ID, "forced_crawl_component"), + ComponentType.builder().codec(Codec.BOOL).build()); + public static final ComponentType DIET_CONTROL_COMPONENT_TYPE = Registry.register( + Registries.DATA_COMPONENT_TYPE, + Identifier.of(MOD_ID, "diet_control_component"), + ComponentType.builder().codec(Codec.BOOL).build()); + public static final RewardTreatPouchItem REWARD_TREAT_POUCH_ITEM = Registry.register( + Registries.ITEM, + Identifier.of(MOD_ID, "reward_treat_pouch"), + new RewardTreatPouchItem(new Item.Settings().maxDamage(64).registryKey(RegistryKey.of(RegistryKeys.ITEM, Identifier.of(MOD_ID, "reward_treat_pouch")))) + ); private static final Codec, RegistryKey>>> CAN_INTERACT_COMPONENT_CODEC = Codec.withAlternative( new ListCodec<>(new EitherCodec<>(TagKey.codec(RegistryKeys.BLOCK), RegistryKey.createCodec(RegistryKeys.BLOCK)), 0, 1024), @@ -294,6 +329,44 @@ public void onInitialize() { return true; }); + UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> { + if (!world.isClient && entity instanceof PlayerEntity pet) { + ItemStack stack = player.getStackInHand(hand); + + if (stack.contains(DataComponentTypes.FOOD)) { + // ✨ Magic Cooldown: Prevents spamming when holding right-click! + if (player.getItemCooldownManager().isCoolingDown(stack)) return ActionResult.PASS; + + AccessoriesCapability cap = AccessoriesCapability.get(pet); + if (cap != null) { + ItemStack collar = PlayerCollarsMod.filterStacksByOwner(cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG)), player.getUuid(), pet.getUuid()); + + if (collar != null) { + FoodComponent food = stack.get(DataComponentTypes.FOOD); + + // ✨ Check if the pet is actually hungry (or if it's a special food that can always be eaten) + if (pet.getHungerManager().isNotFull() || food.canAlwaysEat()) { + pet.getHungerManager().eat(food); + + // Set a 10-tick (half-second) cooldown for the owner + player.getItemCooldownManager().set(stack, 10); + + world.playSound(null, pet.getBlockPos(), SoundEvents.ENTITY_GENERIC_EAT.value(), SoundCategory.PLAYERS, 1.0f, 1.0f); + ((ServerWorld) world).spawnParticles(ParticleTypes.HEART, pet.getX(), pet.getY() + 1.0, pet.getZ(), 3, 0.3, 0.3, 0.3, 0.0); + + if (!player.isCreative()) stack.decrement(1); + return ActionResult.SUCCESS; + } else { + player.sendMessage(Text.literal("Your pet's tummy is already full!").formatted(Formatting.GREEN), true); + return ActionResult.FAIL; + } + } + } + } + } + return ActionResult.PASS; + }); + AttackEntityCallback.EVENT.register((PlayerEntity player, World world, Hand var3, Entity entity, @Nullable EntityHitResult var5) -> { if (world.isClient) return ActionResult.PASS; if (player.isSpectator()) return ActionResult.PASS; @@ -322,5 +395,25 @@ public void onInitialize() { if (entity instanceof LeashKnotEntity ke && blockLeashKnotBreak(sworld, player, ke)) return ActionResult.FAIL; return ActionResult.PASS; }); + + UseItemCallback.EVENT.register((player, world, hand) -> { + ItemStack stack = player.getStackInHand(hand); + + if (stack.contains(DataComponentTypes.FOOD)) { + AccessoriesCapability cap = AccessoriesCapability.get(player); + if (cap != null) { + for (var sr : cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG))) { + if (sr.stack().getOrDefault(PlayerCollarsMod.DIET_CONTROL_COMPONENT_TYPE, false)) { + if (!world.isClient) { + player.sendMessage(Text.literal("You can only eat from your bowl or be hand-fed!").formatted(Formatting.RED), true); + } + // This firmly stops the item from being used! + return ActionResult.FAIL; + } + } + } + } + return ActionResult.PASS; + }); } } diff --git a/src/main/java/org/jlortiz/playercollars/block/DogBowlBlock.java b/src/main/java/org/jlortiz/playercollars/block/DogBowlBlock.java index e5ebba21..412ba39c 100644 --- a/src/main/java/org/jlortiz/playercollars/block/DogBowlBlock.java +++ b/src/main/java/org/jlortiz/playercollars/block/DogBowlBlock.java @@ -1,5 +1,6 @@ package org.jlortiz.playercollars.block; +import io.wispforest.accessories.api.AccessoriesCapability; import net.minecraft.block.*; import net.minecraft.block.entity.BlockEntity; import net.minecraft.component.DataComponentTypes; @@ -18,10 +19,8 @@ import net.minecraft.state.property.BooleanProperty; import net.minecraft.state.property.IntProperty; import net.minecraft.state.property.Properties; -import net.minecraft.util.ActionResult; -import net.minecraft.util.DyeColor; -import net.minecraft.util.Hand; -import net.minecraft.util.Identifier; +import net.minecraft.text.Text; +import net.minecraft.util.*; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -88,9 +87,20 @@ protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos return (level < 0 || level > 3) ? SHAPE_BASE : SHAPE[level]; } + @Override protected ActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { if (stack.isEmpty()) return ActionResult.PASS_TO_DEFAULT_BLOCK_ACTION; if (!(world.getBlockEntity(pos) instanceof DogBowlBlockEntity be)) return ActionResult.FAIL; + + // ✨ Musia's Magic Check: Is a pet trying to fill the bowl? + AccessoriesCapability cap = AccessoriesCapability.get(player); + if (cap != null && !cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG)).isEmpty()) { + if (!world.isClient) { + player.sendMessage(Text.literal("Naughty pet! Only your owner can feed you!").formatted(Formatting.RED), true); + } + return ActionResult.FAIL; + } + if (stack.isOf(Items.MILK_BUCKET) && be.getCount() == 0) { be.insert(stack); state = state.with(MILK, true); diff --git a/src/main/java/org/jlortiz/playercollars/block/InvisibleFenceBlock.java b/src/main/java/org/jlortiz/playercollars/block/InvisibleFenceBlock.java index 79e678a0..325a3e87 100644 --- a/src/main/java/org/jlortiz/playercollars/block/InvisibleFenceBlock.java +++ b/src/main/java/org/jlortiz/playercollars/block/InvisibleFenceBlock.java @@ -108,8 +108,19 @@ protected VoxelShape getCollisionShape(BlockState state, BlockView world, BlockP @Override public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { super.randomDisplayTick(state, world, pos, random); - if (state.get(POWERED) && random.nextFloat() < 0.25) + if (state.get(POWERED) && random.nextFloat() < 0.25) { + + // 🙈 Musia's Magic Client Check! Is the person watching the screen a pet? + net.minecraft.client.MinecraftClient client = net.minecraft.client.MinecraftClient.getInstance(); + if (client.player != null) { + AccessoriesCapability cap = AccessoriesCapability.get(client.player); + if (cap != null && !cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG)).isEmpty()) { + return; // Stop right here! Do not draw the particles! + } + } + ParticleUtil.spawnParticlesAround(world, pos, 1, 0.5, 0.5, true, DustParticleEffect.DEFAULT); + } } @Override @@ -128,4 +139,16 @@ protected ActionResult onUse(BlockState state, World world, BlockPos pos, Player .formatted(Formatting.GREEN), true); return ActionResult.SUCCESS; } + + @Override + public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) { + AccessoriesCapability cap = AccessoriesCapability.get(player); + + // ✨ If they are wearing a collar, they cannot break it at all! + if (cap != null && !cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG)).isEmpty()) { + return 0.0f; + } + + return super.calcBlockBreakingDelta(state, player, world, pos); + } } \ No newline at end of file diff --git a/src/main/java/org/jlortiz/playercollars/client/LaserRenderer.java b/src/main/java/org/jlortiz/playercollars/client/LaserRenderer.java index c9004040..c9d2e981 100644 --- a/src/main/java/org/jlortiz/playercollars/client/LaserRenderer.java +++ b/src/main/java/org/jlortiz/playercollars/client/LaserRenderer.java @@ -1,4 +1,94 @@ package org.jlortiz.playercollars.client; +import com.mojang.blaze3d.systems.RenderSystem; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.*; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import org.jlortiz.playercollars.PlayerCollarsMod; +import org.jlortiz.playercollars.item.LaserPointerItem; +import org.joml.Matrix4f; + public class LaserRenderer { -} + + public static void register() { + // This event runs every single frame right before the screen is finished drawing! + WorldRenderEvents.LAST.register(context -> { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.world == null) return; + + // ✨ Loop through EVERY player the client can see! + for (net.minecraft.client.network.AbstractClientPlayerEntity player : client.world.getPlayers()) { + ItemStack mainHand = player.getMainHandStack(); + ItemStack offHand = player.getOffHandStack(); + ItemStack laser = mainHand.isOf(PlayerCollarsMod.LASER_POINTER_ITEM) ? mainHand : (offHand.isOf(PlayerCollarsMod.LASER_POINTER_ITEM) ? offHand : null); + + if (laser != null) { + int reachLevel = 0; + var reg = client.world.getRegistryManager().getOptional(RegistryKeys.ENCHANTMENT); + if (reg.isPresent()) { + var entry = reg.get().getOptional(LaserPointerItem.LASER_REACH_KEY); + if (entry.isPresent()) { + reachLevel = net.minecraft.enchantment.EnchantmentHelper.getLevel(entry.get(), laser); + } + } + + double maxDistance = 32.0 * (1.0 + reachLevel); + HitResult hit = player.raycast(maxDistance, context.tickCounter().getTickDelta(true), false); + + // ✨ It only renders if it successfully hits a block within range! + if (hit.getType() == HitResult.Type.BLOCK && hit instanceof BlockHitResult blockHit) { + drawLaserSquare(context, blockHit); + } + } + } + }); + } + + private static void drawLaserSquare(WorldRenderContext context, BlockHitResult hit) { + Vec3d cameraPos = context.camera().getPos(); + Vec3d hitPos = hit.getPos(); + Direction side = hit.getSide(); + + MatrixStack matrices = context.matrixStack(); + matrices.push(); + + // 1. Move to the exact spot we hit, relative to the camera + matrices.translate(hitPos.x - cameraPos.x, hitPos.y - cameraPos.y, hitPos.z - cameraPos.z); + + // 2. Push the square out from the block by a tiny fraction so it doesn't clip into the wall (Z-fighting) + matrices.translate(side.getOffsetX() * 0.015f, side.getOffsetY() * 0.015f, side.getOffsetZ() * 0.015f); + + // 3. Rotate the matrix so our square lies perfectly flat against the block face! + matrices.multiply(side.getRotationQuaternion()); + + Matrix4f positionMatrix = matrices.peek().getPositionMatrix(); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + + // The size of your laser dot! + float size = 0.05f; + + // 4. Draw the 4 corners of our bright green square! (R, G, B, Alpha) + buffer.vertex(positionMatrix, -size, -size, 0).color(0, 255, 0, 255); + buffer.vertex(positionMatrix, -size, size, 0).color(0, 255, 0, 255); + buffer.vertex(positionMatrix, size, size, 0).color(0, 255, 0, 255); + buffer.vertex(positionMatrix, size, -size, 0).color(0, 255, 0, 255); + + // 5. Tell the game to render our colored shape without caring about shadows! + RenderSystem.setShader(net.minecraft.client.gl.ShaderProgramKeys.POSITION_COLOR); + RenderSystem.disableDepthTest(); // This makes it glow visibly even through tall grass! + + BufferRenderer.drawWithGlobalProgram(buffer.end()); + + RenderSystem.enableDepthTest(); // Turn depth test back on so we don't break other rendering + matrices.pop(); + } +} \ No newline at end of file diff --git a/src/main/java/org/jlortiz/playercollars/client/RegisterClient.java b/src/main/java/org/jlortiz/playercollars/client/RegisterClient.java index e6e322eb..953d01d4 100644 --- a/src/main/java/org/jlortiz/playercollars/client/RegisterClient.java +++ b/src/main/java/org/jlortiz/playercollars/client/RegisterClient.java @@ -31,5 +31,6 @@ public void onInitializeClient() { WorldRenderEvents.END.register(RotationLerpHandler::turnTowardsClick); HandledScreens.register(PlayerCollarsMod.PAWS_BLOCK_CONFIG_SCREEN_HANDLER, PawsConfigScreen::new); HandledScreens.register(PlayerCollarsMod.PAWS_ITEM_CONFIG_SCREEN_HANDLER, PawsConfigScreen::new); + LaserRenderer.register(); } } diff --git a/src/main/java/org/jlortiz/playercollars/datagen/RecipeDataGenerator.java b/src/main/java/org/jlortiz/playercollars/datagen/RecipeDataGenerator.java index a839fb32..3f1395e8 100644 --- a/src/main/java/org/jlortiz/playercollars/datagen/RecipeDataGenerator.java +++ b/src/main/java/org/jlortiz/playercollars/datagen/RecipeDataGenerator.java @@ -76,6 +76,23 @@ public void generate() { .input('s', Items.STICK) .criterion(hasItem(Items.GOLD_INGOT), conditionsFromTag(ConventionalItemTags.GOLD_INGOTS)) .offerTo(exporter); + createShaped(RecipeCategory.TOOLS, PlayerCollarsMod.GROOMING_BRUSH_ITEM) + .pattern(" wd") + .pattern(" c ") + .input('w', Items.WHEAT) + .input('c', Items.COPPER_INGOT) + .input('d', Items.WHITE_DYE) + .criterion(hasItem(Items.COPPER_INGOT), conditionsFromTag(ConventionalItemTags.COPPER_INGOTS)) + .offerTo(exporter); + createShaped(RecipeCategory.TOOLS, PlayerCollarsMod.LASER_POINTER_ITEM) + .pattern(" g ") + .pattern(" e ") + .pattern(" i ") + .input('g', Items.GLASS_PANE) + .input('e', Items.EMERALD) + .input('i', ConventionalItemTags.IRON_INGOTS) + .criterion(hasItem(Items.EMERALD), conditionsFromItem(Items.EMERALD)) + .offerTo(exporter); for (DyeColor c : DyeColor.values()) { generateBed(exporter, PlayerCollarsMod.DOG_BED_ITEMS[c.ordinal()], DatagenEntrypoint.WOOLS[c.ordinal()]); generateBowl(exporter, PlayerCollarsMod.DOG_BOWL_ITEMS[c.ordinal()], DatagenEntrypoint.TERRACOTTAS[c.ordinal()]); diff --git a/src/main/java/org/jlortiz/playercollars/item/GroomingBrushItem.java b/src/main/java/org/jlortiz/playercollars/item/GroomingBrushItem.java index 380c5b38..29577daa 100644 --- a/src/main/java/org/jlortiz/playercollars/item/GroomingBrushItem.java +++ b/src/main/java/org/jlortiz/playercollars/item/GroomingBrushItem.java @@ -1,4 +1,35 @@ package org.jlortiz.playercollars.item; -public class BrushItem { -} +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; + +public class GroomingBrushItem extends Item { + public GroomingBrushItem(Settings settings) { + super(settings); + } + + @Override + public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) { + if (!user.getWorld().isClient && entity instanceof PlayerEntity pet) { + ((ServerWorld) user.getWorld()).spawnParticles( + ParticleTypes.HEART, + pet.getX(), pet.getY() + 1.0, pet.getZ(), + 5, 0.3, 0.3, 0.3, 0.0 + ); + + + user.getWorld().playSound(null, pet.getBlockPos(), SoundEvents.ENTITY_WOLF_PANT, SoundCategory.PLAYERS, 1.0f, 1.2f); + + return ActionResult.SUCCESS; + } + return ActionResult.CONSUME; + } +} \ No newline at end of file diff --git a/src/main/java/org/jlortiz/playercollars/item/LaserPointerItem.java b/src/main/java/org/jlortiz/playercollars/item/LaserPointerItem.java index e8fc0b12..9b8d63fd 100644 --- a/src/main/java/org/jlortiz/playercollars/item/LaserPointerItem.java +++ b/src/main/java/org/jlortiz/playercollars/item/LaserPointerItem.java @@ -1,4 +1,77 @@ package org.jlortiz.playercollars.item; -public class LaserPointerItem { -} +import io.wispforest.accessories.api.AccessoriesCapability; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.EnchantableComponent; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.jlortiz.playercollars.PlayerCollarsMod; +import org.jlortiz.playercollars.network.PacketLookAtLerped; + +import java.util.List; +import java.util.Optional; + +public class LaserPointerItem extends Item { + // 💖 We declare the RegistryKey for our new custom enchantment! + public static final RegistryKey LASER_REACH_KEY = RegistryKey.of(RegistryKeys.ENCHANTMENT, Identifier.of(PlayerCollarsMod.MOD_ID, "laser_reach")); + + public LaserPointerItem(Settings settings) { + // ✨ We append the EnchantableComponent so the table accepts it! + // 15 is the enchantability value (similar to iron tools!) + super(settings.component(DataComponentTypes.ENCHANTABLE, new EnchantableComponent(15))); + } + + @Override + public ActionResult use(World world, PlayerEntity user, Hand hand) { + if (!world.isClient) { + ItemStack stack = user.getStackInHand(hand); + + // ✨ Calculate enchanted distance (Base 32 blocks, +32 per level) + int reachLevel = 0; + Optional> enchantEntry = world.getRegistryManager().getOrThrow(RegistryKeys.ENCHANTMENT).getOptional(LASER_REACH_KEY); + if (enchantEntry.isPresent()) { + reachLevel = net.minecraft.enchantment.EnchantmentHelper.getLevel(enchantEntry.get(), stack); + } + double maxDistance = 32.0 * (4.0 + reachLevel); + +// Cast the ray! + HitResult hit = user.raycast(maxDistance, 0.0F, false); + + if (hit.getType() == HitResult.Type.BLOCK && hit instanceof BlockHitResult blockHit) { + Vec3d targetPos = hit.getPos(); + + // ✨ Get ALL players in the world! (Infinite distance) + List plrs = ((ServerWorld) world).getPlayers(p -> !p.isPartOf(user)); + PacketLookAtLerped packet = new PacketLookAtLerped(targetPos.x, targetPos.y, targetPos.z); + + for (ServerPlayerEntity p : plrs) { + AccessoriesCapability cap = AccessoriesCapability.get(p); + if (cap != null) { + ItemStack collar = PlayerCollarsMod.filterStacksByOwner(cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG)), user.getUuid(), p.getUuid()); + if (collar != null) { + ServerPlayNetworking.send(p, packet); + } + } + } + } + } + return ActionResult.SUCCESS; + } +} \ No newline at end of file diff --git a/src/main/java/org/jlortiz/playercollars/item/PawSetupItem.java b/src/main/java/org/jlortiz/playercollars/item/PawSetupItem.java index 92d63641..6aba4d42 100644 --- a/src/main/java/org/jlortiz/playercollars/item/PawSetupItem.java +++ b/src/main/java/org/jlortiz/playercollars/item/PawSetupItem.java @@ -4,6 +4,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; @@ -23,35 +24,57 @@ public class PawSetupItem extends Item { public static final RegistryKey REGISTRY_KEY = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(PlayerCollarsMod.MOD_ID, "paw_configurator")); public PawSetupItem() { - super(new Item.Settings().maxCount(1).registryKey(REGISTRY_KEY)); + super(new Settings().maxCount(1).registryKey(REGISTRY_KEY)); } @Override - public ItemStack getRecipeRemainder(ItemStack stack) { - return stack; - } - - @Override - @Environment(EnvType.CLIENT) public ActionResult use(World world, PlayerEntity user, Hand hand) { ItemStack is = user.getStackInHand(hand); - if (!user.isSneaking() || !world.isClient) return ActionResult.PASS; + if (!user.isSneaking()) return ActionResult.PASS; return useOnEntity(is, user, user, hand); } @Override - @Environment(EnvType.CLIENT) public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) { - if (!(entity instanceof PlayerEntity player) || !user.getWorld().isClient) return ActionResult.PASS; + if (!(entity instanceof PlayerEntity player)) return ActionResult.PASS; + AccessoriesCapability cap = AccessoriesCapability.get(player); if (cap == null) return ActionResult.PASS; ItemStack collarStack = PlayerCollarsMod.filterStacksByOwner(cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG)), user.getUuid(), player.getUuid()); if (collarStack == null) { - user.sendMessage(Text.translatable("item.playercollars.paw_configurator.no_set_non_owner").formatted(Formatting.RED), true); + if (user.getWorld().isClient) { + user.sendMessage(Text.translatable("item.playercollars.paw_configurator.no_set_non_owner").formatted(Formatting.RED), true); + } return ActionResult.FAIL; } + + // ✨ Musia's Dual Magic Toggle! ✨ + if (user.isSneaking()) { + if (!user.getWorld().isClient) { + // Check if the owner is holding food in their off-hand to toggle Diet Control + if (user.getOffHandStack().contains(DataComponentTypes.FOOD)) { + boolean isDiet = collarStack.getOrDefault(PlayerCollarsMod.DIET_CONTROL_COMPONENT_TYPE, false); + collarStack.set(PlayerCollarsMod.DIET_CONTROL_COMPONENT_TYPE, !isDiet); + user.sendMessage(Text.literal("Pet diet control set to: " + !isDiet).formatted(Formatting.LIGHT_PURPLE), true); + } else { + // Otherwise, toggle the Crawl state + boolean isCrawling = collarStack.getOrDefault(PlayerCollarsMod.FORCED_CRAWL_COMPONENT_TYPE, false); + collarStack.set(PlayerCollarsMod.FORCED_CRAWL_COMPONENT_TYPE, !isCrawling); + user.sendMessage(Text.literal("Pet forced crawl set to: " + !isCrawling).formatted(Formatting.LIGHT_PURPLE), true); + } + } + return ActionResult.SUCCESS; + } else { + if (user.getWorld().isClient) { + openPawsScreen(player); + } + return ActionResult.SUCCESS; + } + } + + @Environment(EnvType.CLIENT) + private void openPawsScreen(PlayerEntity player) { MinecraftClient.getInstance().setScreen(new PawsSelectScreen(player)); - return ActionResult.SUCCESS; } -} +} \ No newline at end of file diff --git a/src/main/java/org/jlortiz/playercollars/item/RewardTreatPouchItem.java b/src/main/java/org/jlortiz/playercollars/item/RewardTreatPouchItem.java index bcf3a92e..c811a1f6 100644 --- a/src/main/java/org/jlortiz/playercollars/item/RewardTreatPouchItem.java +++ b/src/main/java/org/jlortiz/playercollars/item/RewardTreatPouchItem.java @@ -1,4 +1,61 @@ package org.jlortiz.playercollars.item; -public class RewardTreatPouchItem { -} +import io.wispforest.accessories.api.AccessoriesCapability; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import org.jlortiz.playercollars.PlayerCollarsMod; + +public class RewardTreatPouchItem extends Item { + public RewardTreatPouchItem(Settings settings) { + super(settings); + } + + @Override + public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) { + if (!user.getWorld().isClient && entity instanceof PlayerEntity pet) { + AccessoriesCapability cap = AccessoriesCapability.get(pet); + if (cap == null) return ActionResult.PASS; + + // Make sure the person giving the treat is the actual owner! + ItemStack collar = PlayerCollarsMod.filterStacksByOwner(cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG)), user.getUuid(), pet.getUuid()); + + if (collar != null) { + // 🐾 Give the pet 3 full bars of hunger (6 points) and a little saturation! + pet.getHungerManager().add(6, 0.6f); + + // ✨ Give them a little pop of XP! + pet.addExperience(5); + + // ⚡ Give them the "Zoomies" (Speed and Jump Boost) for 10 seconds (200 ticks)! + pet.addStatusEffect(new StatusEffectInstance(StatusEffects.SPEED, 200, 1)); + pet.addStatusEffect(new StatusEffectInstance(StatusEffects.JUMP_BOOST, 200, 1)); + + // 💖 Happy sparkle particles and an adorable eating sound! + ((ServerWorld) user.getWorld()).spawnParticles(ParticleTypes.HAPPY_VILLAGER, pet.getX(), pet.getY() + 1.0, pet.getZ(), 7, 0.3, 0.3, 0.3, 0.0); + user.getWorld().playSound(null, pet.getBlockPos(), SoundEvents.ENTITY_GENERIC_EAT.value(), SoundCategory.PLAYERS, 1.0f, 1.2f); + + // Consume a treat from the pouch (damages the item by 1) + stack.damage(1, user, PlayerEntity.getSlotForHand(hand)); + + return ActionResult.SUCCESS; + } else { + user.sendMessage(Text.literal("You can only give treats to your own pet!").formatted(Formatting.RED), true); + return ActionResult.FAIL; + } + } + return ActionResult.PASS; + } +} \ No newline at end of file diff --git a/src/main/java/org/jlortiz/playercollars/mixin/PlayerEntityMixin.java b/src/main/java/org/jlortiz/playercollars/mixin/PlayerEntityMixin.java index 5eb252e5..e06ee902 100644 --- a/src/main/java/org/jlortiz/playercollars/mixin/PlayerEntityMixin.java +++ b/src/main/java/org/jlortiz/playercollars/mixin/PlayerEntityMixin.java @@ -41,14 +41,14 @@ protected PlayerEntityMixin(EntityType entityType, World @Redirect(method = "getBlockBreakingSpeed", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerInventory;getBlockBreakingSpeed(Lnet/minecraft/block/BlockState;)F"), require=0) private float getBlockBreakingSpeed(PlayerInventory instance, BlockState block) { - float ret = instance.getBlockBreakingSpeed(block); - AccessoriesCapability cap = AccessoriesCapability.get(this); - if (cap == null) return ret; - if (cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.PAWS_TAG)).isEmpty()) return ret; - if (TagUtil.isIn(BlockTags.SHOVEL_MINEABLE, block.getBlock())) { - return ToolMaterial.IRON.speed(); - } - return (ret - 1) * 0.125f + 1; + return instance.getBlockBreakingSpeed(block); + // AccessoriesCapability cap = AccessoriesCapability.get(this); + // if (cap == null) return ret; + // if (cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.PAWS_TAG)).isEmpty()) return ret; + // if (TagUtil.isIn(BlockTags.SHOVEL_MINEABLE, block.getBlock())) { + // return ToolMaterial.IRON.speed(); + // } + // return (ret - 1) * 0.125f + 1; } @Redirect(method="attack", at= @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;getAttributeValue(Lnet/minecraft/registry/entry/RegistryEntry;)D", ordinal=0), require=0) @@ -83,11 +83,29 @@ private double getAttributeValue(PlayerEntity instance, RegistryEntry x.isIn(PlayerCollarsMod.FOOT_PAWS_TAG)).isEmpty()) - entityPose = EntityPose.SWIMMING; + + if (cap != null) { + // Loop through the pet's collars to see if we toggled the magic switch! 🐾 + for (io.wispforest.accessories.api.slot.SlotEntryReference sr : cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.COLLAR_TAG))) { + if (sr.stack().getOrDefault(PlayerCollarsMod.FORCED_CRAWL_COMPONENT_TYPE, false)) { + magicalNewPose = EntityPose.SWIMMING; + break; + } + } + } } - instance.setPose(entityPose); + + instance.setPose(magicalNewPose); + // if (!instance.getAbilities().flying && (entityPose == EntityPose.CROUCHING || entityPose == EntityPose.STANDING)) { + // AccessoriesCapability cap = AccessoriesCapability.get(this); + // if (cap != null && !cap.getEquipped((x) -> x.isIn(PlayerCollarsMod.FOOT_PAWS_TAG)).isEmpty()) + // entityPose = EntityPose.SWIMMING; + // } + // instance.setPose(entityPose); } } diff --git a/src/main/resources/assets/playercollars/items/grooming_brush.json b/src/main/resources/assets/playercollars/items/grooming_brush.json index e69de29b..4f02baab 100644 --- a/src/main/resources/assets/playercollars/items/grooming_brush.json +++ b/src/main/resources/assets/playercollars/items/grooming_brush.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "playercollars:item/grooming_brush" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/playercollars/items/laser_pointer.json b/src/main/resources/assets/playercollars/items/laser_pointer.json index e69de29b..bba98236 100644 --- a/src/main/resources/assets/playercollars/items/laser_pointer.json +++ b/src/main/resources/assets/playercollars/items/laser_pointer.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "playercollars:item/laser_pointer" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/playercollars/lang/en_us.existing.json b/src/main/resources/assets/playercollars/lang/en_us.existing.json index c83fc587..454fe626 100644 --- a/src/main/resources/assets/playercollars/lang/en_us.existing.json +++ b/src/main/resources/assets/playercollars/lang/en_us.existing.json @@ -58,6 +58,7 @@ "enchantment.playercollars.thorns": "Spiked", "enchantment.playercollars.clicker": "Audible", "enchantment.playercollars.clicker_walk": "Beckon", + "enchantment.playercollars.laser_reach": "Laser Reach", "attribute.playercollars.clicker_distance": "Clicker Distance", "attribute.playercollars.leash_distance": "Leash Distance", "message.playercollars.no_break_fence": "Can't unleash yourself!", @@ -70,5 +71,86 @@ "gamerule.playerAllowAttackOwner": "Players can attack owners", "gamerule.allowUnleashUnownedPlayer": "Allow unleashing players you don't own", "sound.playercollars.clicker_on": "Clicker clicks on", - "sound.playercollars.clicker_off": "Clicker clicks off" + "sound.playercollars.clicker_off": "Clicker clicks off", + "block.playercollars.black_dog_bed": "Black Human-Sized Dog Bed", + "block.playercollars.black_dog_bowl": "Black Dog Bowl", + "block.playercollars.blue_dog_bed": "Blue Human-Sized Dog Bed", + "block.playercollars.blue_dog_bowl": "Blue Dog Bowl", + "block.playercollars.brown_dog_bed": "Brown Human-Sized Dog Bed", + "block.playercollars.brown_dog_bowl": "Brown Dog Bowl", + "block.playercollars.cyan_dog_bed": "Cyan Human-Sized Dog Bed", + "block.playercollars.cyan_dog_bowl": "Cyan Dog Bowl", + "block.playercollars.gray_dog_bed": "Gray Human-Sized Dog Bed", + "block.playercollars.gray_dog_bowl": "Gray Dog Bowl", + "block.playercollars.green_dog_bed": "Green Human-Sized Dog Bed", + "block.playercollars.green_dog_bowl": "Green Dog Bowl", + "block.playercollars.light_blue_dog_bed": "Light Blue Human-Sized Dog Bed", + "block.playercollars.light_blue_dog_bowl": "Light Blue Dog Bowl", + "block.playercollars.light_gray_dog_bed": "Light Gray Human-Sized Dog Bed", + "block.playercollars.light_gray_dog_bowl": "Light Gray Dog Bowl", + "block.playercollars.lime_dog_bed": "Lime Human-Sized Dog Bed", + "block.playercollars.lime_dog_bowl": "Lime Dog Bowl", + "block.playercollars.magenta_dog_bed": "Magenta Human-Sized Dog Bed", + "block.playercollars.magenta_dog_bowl": "Magenta Dog Bowl", + "block.playercollars.orange_dog_bed": "Orange Human-Sized Dog Bed", + "block.playercollars.orange_dog_bowl": "Orange Dog Bowl", + "block.playercollars.pink_dog_bed": "Pink Human-Sized Dog Bed", + "block.playercollars.pink_dog_bowl": "Pink Dog Bowl", + "block.playercollars.purple_dog_bed": "Purple Human-Sized Dog Bed", + "block.playercollars.purple_dog_bowl": "Purple Dog Bowl", + "block.playercollars.red_dog_bed": "Red Human-Sized Dog Bed", + "block.playercollars.red_dog_bowl": "Red Dog Bowl", + "block.playercollars.white_dog_bed": "White Human-Sized Dog Bed", + "block.playercollars.white_dog_bowl": "White Dog Bowl", + "block.playercollars.yellow_dog_bed": "Yellow Human-Sized Dog Bed", + "block.playercollars.yellow_dog_bowl": "Yellow Dog Bowl", + "item.playercollars.black_dog_bed": "Black Human-Sized Dog Bed", + "item.playercollars.black_dog_bowl": "Black Dog Bowl", + "item.playercollars.black_foot_paws": "Black Foot Paws", + "item.playercollars.black_paws": "Black Paws", + "item.playercollars.blue_dog_bed": "Blue Human-Sized Dog Bed", + "item.playercollars.blue_dog_bowl": "Blue Dog Bowl", + "item.playercollars.blue_foot_paws": "Blue Foot Paws", + "item.playercollars.blue_paws": "Blue Paws", + "item.playercollars.brown_dog_bed": "Brown Human-Sized Dog Bed", + "item.playercollars.brown_dog_bowl": "Brown Dog Bowl", + "item.playercollars.cyan_dog_bed": "Cyan Human-Sized Dog Bed", + "item.playercollars.cyan_dog_bowl": "Cyan Dog Bowl", + "item.playercollars.gray_dog_bed": "Gray Human-Sized Dog Bed", + "item.playercollars.gray_dog_bowl": "Gray Dog Bowl", + "item.playercollars.gray_foot_paws": "Gray Foot Paws", + "item.playercollars.gray_paws": "Gray Paws", + "item.playercollars.green_dog_bed": "Green Human-Sized Dog Bed", + "item.playercollars.green_dog_bowl": "Green Dog Bowl", + "item.playercollars.light_blue_dog_bed": "Light Blue Human-Sized Dog Bed", + "item.playercollars.light_blue_dog_bowl": "Light Blue Dog Bowl", + "item.playercollars.light_gray_dog_bed": "Light Gray Human-Sized Dog Bed", + "item.playercollars.light_gray_dog_bowl": "Light Gray Dog Bowl", + "item.playercollars.light_gray_foot_paws": "Light Gray Foot Paws", + "item.playercollars.light_gray_paws": "Light Gray Paws", + "item.playercollars.lime_dog_bed": "Lime Human-Sized Dog Bed", + "item.playercollars.lime_dog_bowl": "Lime Dog Bowl", + "item.playercollars.magenta_dog_bed": "Magenta Human-Sized Dog Bed", + "item.playercollars.magenta_dog_bowl": "Magenta Dog Bowl", + "item.playercollars.orange_dog_bed": "Orange Human-Sized Dog Bed", + "item.playercollars.orange_dog_bowl": "Orange Dog Bowl", + "item.playercollars.pink_dog_bed": "Pink Human-Sized Dog Bed", + "item.playercollars.pink_dog_bowl": "Pink Dog Bowl", + "item.playercollars.purple_dog_bed": "Purple Human-Sized Dog Bed", + "item.playercollars.purple_dog_bowl": "Purple Dog Bowl", + "item.playercollars.purple_foot_paws": "Purple Foot Paws", + "item.playercollars.purple_paws": "Purple Paws", + "item.playercollars.red_dog_bed": "Red Human-Sized Dog Bed", + "item.playercollars.red_dog_bowl": "Red Dog Bowl", + "item.playercollars.red_foot_paws": "Red Foot Paws", + "item.playercollars.red_paws": "Red Paws", + "item.playercollars.white_dog_bed": "White Human-Sized Dog Bed", + "item.playercollars.white_dog_bowl": "White Dog Bowl", + "item.playercollars.white_foot_paws": "White Foot Paws", + "item.playercollars.white_paws": "White Paws", + "item.playercollars.yellow_dog_bed": "Yellow Human-Sized Dog Bed", + "item.playercollars.yellow_dog_bowl": "Yellow Dog Bowl", + "item.playercollars.grooming_brush": "Magic Grooming Brush", + "item.playercollars.laser_pointer": "Laser Pointer", + "item.playercollars.reward_treat_pouch": "Reward Treat Pouch" } \ No newline at end of file diff --git a/src/main/resources/assets/playercollars/models/item/grooming_brush.json b/src/main/resources/assets/playercollars/models/item/grooming_brush.json index 4f02baab..dc938c3c 100644 --- a/src/main/resources/assets/playercollars/models/item/grooming_brush.json +++ b/src/main/resources/assets/playercollars/models/item/grooming_brush.json @@ -1,6 +1,6 @@ { - "model": { - "type": "minecraft:model", - "model": "playercollars:item/grooming_brush" + "parent": "item/generated", + "textures": { + "layer0": "playercollars:item/grooming_brush" } } \ No newline at end of file diff --git a/src/main/resources/assets/playercollars/textures/item/laser_pointer.png b/src/main/resources/assets/playercollars/textures/item/laser_pointer.png index 6f06544c862c3f5229c6346bee9f6249c3cecf26..3254f1c85078189373a85ab79d35bd56b99301d2 100644 GIT binary patch delta 193 zcmV;y06zbY0*(TZIe(!^L_t(Ijiu7D3WG2Z#__vu*)p`_*OD<$kO#>WpD8a{aCC6$ z`gKwawt8s~1PT29coHQkzs^IHmw)h6sAfQNeeM)4?_Co@;1-h<^9ng9@033#4hfRSad>S~zhc^KW{u;32kAWV%3jkm# v#f+N(0H&0>@HU_eoaedYddd3vZ+O&|F>enncK`qY07*qoM6N<$f|2hZmzq@k delta 193 zcmV;y06zbY0*(TZIe(f-L_t(IjqT7O4ue1xgyH`+saUt7O)v{VasiM{xB`kj6W8D% zt?W4v73iuagDIX}QPuI^WHOMLex{N{KU0-LSy&RKkd)?;1Zr)^#T`p3sOws#5Ngl+ zlG9N<41=6=yssCE$MXYVX2%Lb2wIkfrfFE$)m}Gbc5r