From 4c0a781cdceadc69348f53d5ac68a0ea1164b418 Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Tue, 23 Apr 2024 00:01:55 +0800 Subject: [PATCH] =?UTF-8?q?=E8=9F=B9=E9=92=B3=E5=AE=9E=E7=8E=B0=EF=BC=9A?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=89=8B=E9=95=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../anvilcraft/api/entity/EntityHelper.java | 12 +++ .../attribute/EntityReachAttribute.java | 18 +++++ .../dev/dubhe/anvilcraft/init/ModItems.java | 5 +- .../dubhe/anvilcraft/item/CrabClawItem.java | 73 +++++++++++++++++++ .../anvilcraft/mixin/LivingEntityMixin.java | 16 ++++ .../accessor/ItemInHandRendererAccessor.java | 17 +++++ .../mixin/accessor/MinecraftAccessor.java | 11 +++ .../resources/anvilcraft-common.mixins.json | 5 +- fabric/build.gradle | 8 ++ .../fabric/EntityReachAttributeImpl.java | 23 ++++++ .../fabric/CustomDataPersistentState.java | 56 ++++++++++++++ .../api/entity/fabric/EntityHelperImpl.java | 11 +++ .../forge/EntityReachAttributeImpl.java | 18 +++++ .../api/entity/forge/EntityHelperImpl.java | 11 +++ settings.gradle | 5 ++ 15 files changed, 286 insertions(+), 3 deletions(-) create mode 100644 common/src/main/java/dev/dubhe/anvilcraft/api/entity/EntityHelper.java create mode 100644 common/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/EntityReachAttribute.java create mode 100644 common/src/main/java/dev/dubhe/anvilcraft/item/CrabClawItem.java create mode 100644 common/src/main/java/dev/dubhe/anvilcraft/mixin/LivingEntityMixin.java create mode 100644 common/src/main/java/dev/dubhe/anvilcraft/mixin/accessor/ItemInHandRendererAccessor.java create mode 100644 common/src/main/java/dev/dubhe/anvilcraft/mixin/accessor/MinecraftAccessor.java create mode 100644 fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/fabric/EntityReachAttributeImpl.java create mode 100644 fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/fabric/CustomDataPersistentState.java create mode 100644 fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/fabric/EntityHelperImpl.java create mode 100644 forge/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/forge/EntityReachAttributeImpl.java create mode 100644 forge/src/main/java/dev/dubhe/anvilcraft/api/entity/forge/EntityHelperImpl.java diff --git a/common/src/main/java/dev/dubhe/anvilcraft/api/entity/EntityHelper.java b/common/src/main/java/dev/dubhe/anvilcraft/api/entity/EntityHelper.java new file mode 100644 index 000000000..820f7918f --- /dev/null +++ b/common/src/main/java/dev/dubhe/anvilcraft/api/entity/EntityHelper.java @@ -0,0 +1,12 @@ +package dev.dubhe.anvilcraft.api.entity; + +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.LivingEntity; + +public class EntityHelper { + @ExpectPlatform + public static CompoundTag getCustomData(LivingEntity entity) { + return null; + } +} diff --git a/common/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/EntityReachAttribute.java b/common/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/EntityReachAttribute.java new file mode 100644 index 000000000..e3b810fe4 --- /dev/null +++ b/common/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/EntityReachAttribute.java @@ -0,0 +1,18 @@ +package dev.dubhe.anvilcraft.api.entity.attribute; + +import com.google.common.collect.Multimap; +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; + +import java.util.function.Supplier; + +public class EntityReachAttribute { + + @ExpectPlatform + public static Supplier> getRangeModifierSupplier( + AttributeModifier modifier + ) { + return null; + } +} diff --git a/common/src/main/java/dev/dubhe/anvilcraft/init/ModItems.java b/common/src/main/java/dev/dubhe/anvilcraft/init/ModItems.java index 9ae9c2010..78241e964 100644 --- a/common/src/main/java/dev/dubhe/anvilcraft/init/ModItems.java +++ b/common/src/main/java/dev/dubhe/anvilcraft/init/ModItems.java @@ -9,6 +9,7 @@ import dev.dubhe.anvilcraft.data.recipe.crafting.ShapedTagRecipeBuilder; import dev.dubhe.anvilcraft.item.AnvilHammerItem; import dev.dubhe.anvilcraft.item.CapacitorItem; +import dev.dubhe.anvilcraft.item.CrabClawItem; import dev.dubhe.anvilcraft.item.CursedItem; import dev.dubhe.anvilcraft.item.GeodeItem; import dev.dubhe.anvilcraft.item.MagnetItem; @@ -558,8 +559,8 @@ public void appendHoverText( .unlockedBy(AnvilCraftDatagen.hasItem(Items.IRON_INGOT), RegistrateRecipeProvider.has(Items.IRON_INGOT)) .save(provider)) .register(); - public static final ItemEntry CRAB_CLAW = REGISTRATE - .item("crab_claw", Item::new) + public static final ItemEntry CRAB_CLAW = REGISTRATE + .item("crab_claw", CrabClawItem::new) .model((ctx, provider) -> { }) .register(); diff --git a/common/src/main/java/dev/dubhe/anvilcraft/item/CrabClawItem.java b/common/src/main/java/dev/dubhe/anvilcraft/item/CrabClawItem.java new file mode 100644 index 000000000..b36dc9863 --- /dev/null +++ b/common/src/main/java/dev/dubhe/anvilcraft/item/CrabClawItem.java @@ -0,0 +1,73 @@ +package dev.dubhe.anvilcraft.item; + +import com.google.common.collect.Multimap; +import dev.dubhe.anvilcraft.api.entity.EntityHelper; +import dev.dubhe.anvilcraft.api.entity.attribute.EntityReachAttribute; +import dev.dubhe.anvilcraft.init.ModItems; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; + +import java.util.UUID; +import java.util.function.Supplier; + +public class CrabClawItem extends Item { + + public static final AttributeModifier rangeAttributeModifier = + new AttributeModifier( + UUID.fromString("ea7bed72-603d-4990-87b6-24abe91ea523"), + "RangeModifier", + 3, + AttributeModifier.Operation.ADDITION + ); + + public static final String CRAB_CLAW_MARKER = "crabClaw"; + public static final String DUAL_CRAB_CLAW_MARKER = "dualCrabClaw"; + + private static final Supplier> rangeModifier + = EntityReachAttribute.getRangeModifierSupplier(rangeAttributeModifier); + + public CrabClawItem(Properties properties) { + super(properties); + } + + public static void holdingCrabClawIncreasesRange(LivingEntity entity) { + if (!(entity instanceof Player player)) return; + if (entity.level().isClientSide) return; + CompoundTag customData = EntityHelper.getCustomData(entity); + boolean inOffHand = ModItems.CRAB_CLAW.isIn(player.getOffhandItem()); + boolean inMainHand = ModItems.CRAB_CLAW.isIn(player.getMainHandItem()); + boolean holdingDualCrabClaw = inOffHand && inMainHand; + boolean holdingCrabClaw = inOffHand || inMainHand; + boolean wasHoldingCrabClaw = customData.contains(CRAB_CLAW_MARKER); + boolean wasHoldingDualCrabClaw = customData.contains(DUAL_CRAB_CLAW_MARKER); + if (!holdingCrabClaw) { + player.getAttributes() + .removeAttributeModifiers(rangeModifier.get()); + if (wasHoldingCrabClaw) { + customData.remove(CRAB_CLAW_MARKER); + } + } else { + player.getAttributes() + .addTransientAttributeModifiers(rangeModifier.get()); + if (!wasHoldingDualCrabClaw) { + customData.putBoolean(CRAB_CLAW_MARKER, true); + } + } + + if (!holdingDualCrabClaw) { + if (wasHoldingDualCrabClaw) { + customData.remove(DUAL_CRAB_CLAW_MARKER); + } + } else { + if (!wasHoldingDualCrabClaw) { + customData.putBoolean(DUAL_CRAB_CLAW_MARKER, true); + } + } + + } + +} diff --git a/common/src/main/java/dev/dubhe/anvilcraft/mixin/LivingEntityMixin.java b/common/src/main/java/dev/dubhe/anvilcraft/mixin/LivingEntityMixin.java new file mode 100644 index 000000000..8da9df142 --- /dev/null +++ b/common/src/main/java/dev/dubhe/anvilcraft/mixin/LivingEntityMixin.java @@ -0,0 +1,16 @@ +package dev.dubhe.anvilcraft.mixin; + +import dev.dubhe.anvilcraft.item.CrabClawItem; +import net.minecraft.world.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LivingEntity.class) +public class LivingEntityMixin { + @Inject(method = "tick", at = @At("HEAD")) + void onLivingEntityTick(CallbackInfo ci) { + CrabClawItem.holdingCrabClawIncreasesRange((LivingEntity) (Object) this); + } +} diff --git a/common/src/main/java/dev/dubhe/anvilcraft/mixin/accessor/ItemInHandRendererAccessor.java b/common/src/main/java/dev/dubhe/anvilcraft/mixin/accessor/ItemInHandRendererAccessor.java new file mode 100644 index 000000000..f6bf49f23 --- /dev/null +++ b/common/src/main/java/dev/dubhe/anvilcraft/mixin/accessor/ItemInHandRendererAccessor.java @@ -0,0 +1,17 @@ +package dev.dubhe.anvilcraft.mixin.accessor; + +import net.minecraft.client.renderer.ItemInHandRenderer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + + +@Mixin(ItemInHandRenderer.class) +public interface ItemInHandRendererAccessor { + @Accessor + ItemStack getMainHandItem(); + + @Accessor + ItemStack getOffHandItem(); +} diff --git a/common/src/main/java/dev/dubhe/anvilcraft/mixin/accessor/MinecraftAccessor.java b/common/src/main/java/dev/dubhe/anvilcraft/mixin/accessor/MinecraftAccessor.java new file mode 100644 index 000000000..13b04a704 --- /dev/null +++ b/common/src/main/java/dev/dubhe/anvilcraft/mixin/accessor/MinecraftAccessor.java @@ -0,0 +1,11 @@ +package dev.dubhe.anvilcraft.mixin.accessor; + +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Minecraft.class) +public interface MinecraftAccessor { + @Accessor("pausePartialTick") + float getPausePartialTick(); +} diff --git a/common/src/main/resources/anvilcraft-common.mixins.json b/common/src/main/resources/anvilcraft-common.mixins.json index 35e41669b..01c7555ca 100644 --- a/common/src/main/resources/anvilcraft-common.mixins.json +++ b/common/src/main/resources/anvilcraft-common.mixins.json @@ -14,13 +14,16 @@ "DispenseItemEmptyBucketBehaviorMixin", "DispenseItemWaterBottleBehaviorMixin", "ItemEntityMixin", + "LivingEntityMixin", "LootContextParamSetsAccessor", "SolidBucketItemMixin", "accessor.BaseSpawnerAccessor", "accessor.FallingBlockEntityAccessor" ], "client": [ - "LevelRendererMixin" + "LevelRendererMixin", + "accessor.ItemInHandRendererAccessor", + "accessor.MinecraftAccessor" ], "injectors": { "defaultRequire": 1 diff --git a/fabric/build.gradle b/fabric/build.gradle index 0c7ffdf63..573d50627 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -83,6 +83,10 @@ repositories { maven { url = "https://jitpack.io/" } // Mixin Extras, Fabric ASM maven { url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" } maven { url = "https://maven.saps.dev/minecraft" } // saps.dev Maven (KubeJS and Rhino) + maven { // Reach Entity Attributes + url = "https://maven.jamieswhiteshirt.com/libs-release" + content { includeGroup("com.jamieswhiteshirt") } + } } dependencies { @@ -125,6 +129,10 @@ dependencies { // cloth config api modImplementation(fabric.clothConfig) include(fabric.clothConfig) + + //reach-entity-attributes + modImplementation(fabric.reachEntityAttributes) + include(fabric.reachEntityAttributes) } diff --git a/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/fabric/EntityReachAttributeImpl.java b/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/fabric/EntityReachAttributeImpl.java new file mode 100644 index 000000000..b2657e753 --- /dev/null +++ b/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/fabric/EntityReachAttributeImpl.java @@ -0,0 +1,23 @@ +package dev.dubhe.anvilcraft.api.entity.attribute.fabric; + +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; +import com.jamieswhiteshirt.reachentityattributes.ReachEntityAttributes; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; + +import java.util.function.Supplier; + +public class EntityReachAttributeImpl { + public static Supplier> getRangeModifierSupplier( + AttributeModifier modifier + ) { + return Suppliers.memoize(() -> + ImmutableMultimap.of( + ReachEntityAttributes.REACH, modifier, + ReachEntityAttributes.ATTACK_RANGE, modifier + ) + ); + } +} diff --git a/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/fabric/CustomDataPersistentState.java b/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/fabric/CustomDataPersistentState.java new file mode 100644 index 000000000..a1c97af8d --- /dev/null +++ b/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/fabric/CustomDataPersistentState.java @@ -0,0 +1,56 @@ +package dev.dubhe.anvilcraft.api.entity.fabric; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.SavedData; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class CustomDataPersistentState extends SavedData { + private static final String PLAYER_DATA_TAG = "AnvilCraftData"; + private final Map playerCustomData = new ConcurrentHashMap<>(); + + static CompoundTag getPlayerCustomData(LivingEntity player) { + CustomDataPersistentState state = getServerState(player.level().getServer()); + return state.playerCustomData.computeIfAbsent( + player.getUUID(), + it -> new CompoundTag() + ); + } + + public static CustomDataPersistentState getServerState(MinecraftServer server) { + var dataStorage = server.getLevel(Level.OVERWORLD).getDataStorage(); + var state = dataStorage.computeIfAbsent( + CustomDataPersistentState::createFromCompoundTag, + CustomDataPersistentState::new, + "anvilcraft" + ); + state.setDirty(); + return state; + } + + public static CustomDataPersistentState createFromCompoundTag(CompoundTag tag) { + CustomDataPersistentState state = new CustomDataPersistentState(); + CompoundTag playersTag = tag.getCompound(PLAYER_DATA_TAG); + playersTag.getAllKeys().forEach(it -> { + CompoundTag compoundTag = playersTag.getCompound(it); + UUID uuid = UUID.fromString(it); + state.playerCustomData.put(uuid, compoundTag); + }); + return state; + } + + @Override + public CompoundTag save(CompoundTag compoundTag) { + CompoundTag dataTag = new CompoundTag(); + this.playerCustomData.forEach((uuid, tag) -> { + dataTag.put(uuid.toString(), tag); + }); + compoundTag.put(PLAYER_DATA_TAG, dataTag); + return compoundTag; + } +} diff --git a/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/fabric/EntityHelperImpl.java b/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/fabric/EntityHelperImpl.java new file mode 100644 index 000000000..7c89fbe09 --- /dev/null +++ b/fabric/src/main/java/dev/dubhe/anvilcraft/api/entity/fabric/EntityHelperImpl.java @@ -0,0 +1,11 @@ +package dev.dubhe.anvilcraft.api.entity.fabric; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.LivingEntity; + +public class EntityHelperImpl { + + public static CompoundTag getCustomData(LivingEntity entity) { + return CustomDataPersistentState.getPlayerCustomData(entity); + } +} diff --git a/forge/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/forge/EntityReachAttributeImpl.java b/forge/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/forge/EntityReachAttributeImpl.java new file mode 100644 index 000000000..515e6778e --- /dev/null +++ b/forge/src/main/java/dev/dubhe/anvilcraft/api/entity/attribute/forge/EntityReachAttributeImpl.java @@ -0,0 +1,18 @@ +package dev.dubhe.anvilcraft.api.entity.attribute.forge; + +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraftforge.common.ForgeMod; + +import java.util.function.Supplier; + +public class EntityReachAttributeImpl { + public static Supplier> getRangeModifierSupplier( + AttributeModifier modifier + ) { + return Suppliers.memoize(() -> ImmutableMultimap.of(ForgeMod.BLOCK_REACH.get(), modifier)); + } +} diff --git a/forge/src/main/java/dev/dubhe/anvilcraft/api/entity/forge/EntityHelperImpl.java b/forge/src/main/java/dev/dubhe/anvilcraft/api/entity/forge/EntityHelperImpl.java new file mode 100644 index 000000000..b4b92c2cf --- /dev/null +++ b/forge/src/main/java/dev/dubhe/anvilcraft/api/entity/forge/EntityHelperImpl.java @@ -0,0 +1,11 @@ +package dev.dubhe.anvilcraft.api.entity.forge; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.LivingEntity; + +public class EntityHelperImpl { + + public static CompoundTag getCustomData(LivingEntity entity) { + return entity.getPersistentData(); + } +} diff --git a/settings.gradle b/settings.gradle index 81eee6a50..4dd5fd063 100644 --- a/settings.gradle +++ b/settings.gradle @@ -30,6 +30,8 @@ dependencyResolutionManagement { def modMenuVersion = "7.1.0" def jadeFabricVersion = "11.8.0" def registrateFabricVersion = "1.4.5-MC1.20.1" + def reachEntityAttributesVersion = "2.4.0" + // Forge def forgeVersion = "47.2.0" @@ -96,6 +98,9 @@ dependencyResolutionManagement { def clothConfig = version("clothConfig", clothConfigVersion) library("clothConfig", "me.shedaniel.cloth", "cloth-config-fabric").versionRef(clothConfig) + + def reachEntityAttributes = version("reach-entity-attributes", reachEntityAttributesVersion) + library("reachEntityAttributes", "com.jamieswhiteshirt", "reach-entity-attributes").versionRef(reachEntityAttributes) } forge {