diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/WildBackport.java b/common/src/main/java/com/cursedcauldron/wildbackport/WildBackport.java index cd14212..3c7ee52 100644 --- a/common/src/main/java/com/cursedcauldron/wildbackport/WildBackport.java +++ b/common/src/main/java/com/cursedcauldron/wildbackport/WildBackport.java @@ -4,6 +4,8 @@ import org.slf4j.Logger; import com.cursedcauldron.wildbackport.client.registry.WBParticleTypes; import com.cursedcauldron.wildbackport.client.registry.WBSoundEvents; +import com.cursedcauldron.wildbackport.common.entities.access.Recovery; +import com.cursedcauldron.wildbackport.common.items.CompassItemPropertyFunction; import com.cursedcauldron.wildbackport.common.registry.Instruments; import com.cursedcauldron.wildbackport.common.registry.WBBiomes; import com.cursedcauldron.wildbackport.common.registry.WBBlockEntities; @@ -33,6 +35,13 @@ import com.cursedcauldron.wildbackport.common.tag.WBGameEventTags; import com.cursedcauldron.wildbackport.common.tag.WBItemTags; import com.mojang.logging.LogUtils; +import net.minecraft.client.renderer.item.ItemProperties; +import net.minecraft.core.BlockPos; +import net.minecraft.core.GlobalPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; + //<> public class WildBackport { @@ -79,14 +88,18 @@ public class WildBackport { WBItemTags.TAGS.bootstrap(); InstrumentTags.TAGS.bootstrap(); - //ItemProperties.register( - // WBItems.RECOVERY_COMPASS.get(), - // new ResourceLocation("angle"), - // new CompassItemPropertyFunction((level, stack, entity) -> { - // return entity instanceof Player player - // ? Recovery.of(player).getLastDeathLocation().orElse(null) - // : null; - // }) - //); + ItemProperties.register( + WBItems.RECOVERY_COMPASS.get(), + new ResourceLocation("angle"), + new CompassItemPropertyFunction((level, stack, entity) -> { + //if (entity instanceof Player player) + // System.out.println( + // "ALEC: " + Recovery.of(player).getLastDeathLocation() + // ); + return entity instanceof Player player + ? Recovery.of(player).getLastDeathLocation().orElse(null) + : null; + }) + ); } } diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/utils/GlobalPosEntityDataSerializer.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/utils/GlobalPosEntityDataSerializer.java new file mode 100644 index 0000000..f2adf09 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/utils/GlobalPosEntityDataSerializer.java @@ -0,0 +1,42 @@ +package com.cursedcauldron.wildbackport.common.utils; + +import net.minecraft.core.GlobalPos; +import net.minecraft.core.Registry; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.syncher.EntityDataSerializer; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; + +public class GlobalPosEntityDataSerializer implements EntityDataSerializer { + public static final GlobalPosEntityDataSerializer INSTANCE + = new GlobalPosEntityDataSerializer(); + public static final OptionalEntityDataSerializer + OPTIONAL_INSTANCE = new OptionalEntityDataSerializer<>(INSTANCE); + + static { + EntityDataSerializers.registerSerializer(INSTANCE); + EntityDataSerializers.registerSerializer(OPTIONAL_INSTANCE); + } + + @Override + public GlobalPos copy(GlobalPos object) { + return object; + } + + @Override + public GlobalPos read(FriendlyByteBuf fbb) { + return GlobalPos.of( + ResourceKey.create( + Registry.DIMENSION_REGISTRY, new ResourceLocation(fbb.readUtf()) + ), + fbb.readBlockPos() + ); + } + + @Override + public void write(FriendlyByteBuf fbb, GlobalPos obj) { + fbb.writeUtf(obj.dimension().location().toString()); + fbb.writeBlockPos(obj.pos()); + } +} diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/common/utils/OptionalEntityDataSerializer.java b/common/src/main/java/com/cursedcauldron/wildbackport/common/utils/OptionalEntityDataSerializer.java new file mode 100644 index 0000000..a4a3b7c --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/common/utils/OptionalEntityDataSerializer.java @@ -0,0 +1,31 @@ +package com.cursedcauldron.wildbackport.common.utils; + +import java.util.Optional; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.syncher.EntityDataSerializer; + +public class OptionalEntityDataSerializer + implements EntityDataSerializer> { + final EntityDataSerializer inner; + + public OptionalEntityDataSerializer(EntityDataSerializer inner) { + this.inner = inner; + } + + @Override + public Optional copy(Optional object) { + return object.map(this.inner::copy); + } + + @Override + public Optional read(FriendlyByteBuf fbb) { + return fbb.readBoolean() ? Optional.of(this.inner.read(fbb)) : Optional.empty(); + } + + @Override + public void write(FriendlyByteBuf fbb, Optional object) { + fbb.writeBoolean(object.isPresent()); + object.ifPresent(innerObj -> this.inner.write(fbb, innerObj)); + } +} diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/common/PlayerMixin.java b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/common/PlayerMixin.java index 568bf9f..698cdb8 100644 --- a/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/common/PlayerMixin.java +++ b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/common/PlayerMixin.java @@ -2,33 +2,63 @@ package com.cursedcauldron.wildbackport.core.mixin.common; import java.util.Optional; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + import com.cursedcauldron.wildbackport.WildBackport; import com.cursedcauldron.wildbackport.common.entities.Warden; import com.cursedcauldron.wildbackport.common.entities.access.Recovery; import com.cursedcauldron.wildbackport.common.entities.access.WardenTracker; import com.cursedcauldron.wildbackport.common.entities.warden.WardenSpawnTracker; +import com.cursedcauldron.wildbackport.common.utils.GlobalPosEntityDataSerializer; +import com.mojang.authlib.GameProfile; import com.mojang.serialization.Dynamic; + +import net.minecraft.core.BlockPos; import net.minecraft.core.GlobalPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; -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; +import net.minecraft.world.level.Level; //<> @Mixin(Player.class) -public class PlayerMixin implements WardenTracker, Recovery { - private final Player player = Player.class.cast(this); - private WardenSpawnTracker spawnTracker = new WardenSpawnTracker(0, 0, 0); +public abstract class PlayerMixin + extends LivingEntity implements WardenTracker, Recovery { + private static final EntityDataAccessor> + DATA_LAST_DEATH_LOCATION_ID = SynchedEntityData.defineId( + Player.class, GlobalPosEntityDataSerializer.OPTIONAL_INSTANCE + ); + + protected PlayerMixin(EntityType entityType, Level level) { + super(entityType, level); + throw new AssertionError(); + } + + @Unique + private WardenSpawnTracker spawnTracker; + + @Unique private Optional lastDeathLocation = Optional.empty(); + @Inject(method = "", at = @At("TAIL")) + private void wb$init( + Level alec1, BlockPos alec2, float alec3, GameProfile alec4, CallbackInfo ci + ) { + this.spawnTracker = new WardenSpawnTracker(0, 0, 0); + } + @Inject(method = "tick", at = @At("TAIL")) private void wb$tick(CallbackInfo ci) { - if (!player.level.isClientSide) + if (!((Player) (Object) this).level.isClientSide) this.spawnTracker.tick(); } @@ -39,6 +69,12 @@ public class PlayerMixin implements WardenTracker, Recovery { .parse(new Dynamic<>(NbtOps.INSTANCE, tag.get("warden_spawn_tracker"))) .resultOrPartial(WildBackport.LOGGER::error) .ifPresent(tracker -> this.spawnTracker = tracker); + + if (tag.contains("last_death_location", 10)) + GlobalPos.CODEC + .parse(new Dynamic<>(NbtOps.INSTANCE, tag.get("last_death_location"))) + .resultOrPartial(WildBackport.LOGGER::error) + .ifPresent(pos -> this.setLastDeathLocation(Optional.of(pos))); } @Inject(method = "addAdditionalSaveData", at = @At("TAIL")) @@ -46,12 +82,24 @@ public class PlayerMixin implements WardenTracker, Recovery { WardenSpawnTracker.CODEC.encodeStart(NbtOps.INSTANCE, this.spawnTracker) .resultOrPartial(WildBackport.LOGGER::error) .ifPresent(tracker -> tag.put("warden_spawn_Tracker", tracker)); + + this.getLastDeathLocation().ifPresent( + pos + -> GlobalPos.CODEC.encodeStart(NbtOps.INSTANCE, pos) + .resultOrPartial(WildBackport.LOGGER::error) + .ifPresent(serialized -> tag.put("last_death_location", serialized)) + ); + } + + @Inject(method = "defineSynchedData", at = @At("TAIL")) + private void wb$defineSynchedData(CallbackInfo ci) { + this.entityData.define(DATA_LAST_DEATH_LOCATION_ID, Optional.empty()); } @Inject(method = "blockUsingShield", at = @At("HEAD")) private void wb$blockShield(LivingEntity entity, CallbackInfo ci) { if (entity instanceof Warden) - player.disableShield(true); + ((Player) (Object) this).disableShield(true); } @Override @@ -61,11 +109,11 @@ public class PlayerMixin implements WardenTracker, Recovery { @Override public Optional getLastDeathLocation() { - return this.lastDeathLocation; + return this.entityData.get(DATA_LAST_DEATH_LOCATION_ID); } @Override public void setLastDeathLocation(Optional location) { - this.lastDeathLocation = location; + this.entityData.set(DATA_LAST_DEATH_LOCATION_ID, location); } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/common/ServerPlayerMixin.java b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/common/ServerPlayerMixin.java new file mode 100644 index 0000000..19086f9 --- /dev/null +++ b/common/src/main/java/com/cursedcauldron/wildbackport/core/mixin/common/ServerPlayerMixin.java @@ -0,0 +1,32 @@ +package com.cursedcauldron.wildbackport.core.mixin.common; + +import java.util.Optional; + +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; + +import com.cursedcauldron.wildbackport.common.entities.access.Recovery; + +import net.minecraft.core.GlobalPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.player.Player; + +@Mixin(ServerPlayer.class) +public class ServerPlayerMixin { + @Inject(method = "die", at = @At("HEAD")) + private void wb$die(DamageSource ds, CallbackInfo ci) { + var self = (Player) (Object) this; + Recovery.of(self).setLastDeathLocation( + Optional.of(GlobalPos.of(self.level.dimension(), self.blockPosition())) + ); + } + + @Inject(method = "restoreFrom", at = @At("HEAD")) + private void wb$restoreFrom(ServerPlayer sp, boolean bl, CallbackInfo ci) { + Recovery.of((Player) (Object) this) + .setLastDeathLocation(Recovery.of(sp).getLastDeathLocation()); + } +} diff --git a/common/src/main/resources/data/minecraft/recipes/recovery_compass.json b/common/src/main/resources/data/minecraft/recipes/recovery_compass.json new file mode 100644 index 0000000..c904c5c --- /dev/null +++ b/common/src/main/resources/data/minecraft/recipes/recovery_compass.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "key": { + "C": { + "item": "minecraft:compass" + }, + "S": { + "item": "minecraft:echo_shard" + } + }, + "pattern": [ + "SSS", + "SCS", + "SSS" + ], + "result": { + "item": "minecraft:recovery_compass" + } +} diff --git a/common/src/main/resources/wildbackport-common.mixins.json b/common/src/main/resources/wildbackport-common.mixins.json index e8128e6..8b18cd1 100644 --- a/common/src/main/resources/wildbackport-common.mixins.json +++ b/common/src/main/resources/wildbackport-common.mixins.json @@ -1,67 +1,68 @@ { - "required": true, - "minVersion": "0.8", - "package": "com.cursedcauldron.wildbackport.core.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "access.ActivityAccessor", - "access.AxeItemAccessor", - "access.BooleanValueAccessor", - "access.CriteriaTriggersAccessor", - "access.DamageSourceAccessor", - "access.DoorBlockAccessor", - "access.FireBlockAccessor", - "access.GameRulesAccessor", - "access.MemoryModuleTypeAccessor", - "access.MobEffectAccessor", - "access.ModelPartAccessor", - "access.OverworldBiomesAccessor", - "access.PointedDripstoneBlockAccessor", - "access.PressurePlateBlockAccessor", - "access.RecordItemAccessor", - "access.RenderTypeAccessor", - "access.SensorTypeAccessor", - "access.SheetsAccessor", - "access.SimpleParticleTypeAccessor", - "access.StairBlockAccessor", - "access.StructureFeatureAccessor", - "access.StructureTemplatePoolAccessor", - "access.TrapDoorBlockAccessor", - "access.TreeDecoratorTypeAccessor", - "access.TreeFeatureAccessor", - "access.TrunkPlacerTypeAccessor", - "access.WalkNodeEvaluatorAccessor", - "access.WoodButtonBlockAccessor", - "access.WoodTypeAccessor", - "common.ItemsMixin", - "common.BlockEntityTypeMixin", - "common.FlyNodeEvaluatorMixin", - "common.LivingEntityMixin", - "common.MobEffectMixin", - "common.MobEffectMixin$MobEffectInstanceMixin", - "common.NoteBlockMixin", - "common.PathfinderMobMixin", - "common.PlayerMixin", - "common.PointedDripstoneBlockMixin", - "common.SculkSensorBlockEntityMixin", - "common.SculkSensorBlockMixin", - "common.SlimeMixin", - "common.VibrationListenerMixin", - "extension.BoatTypeMixin", - "extension.PoseMixin", - "network.ClientboundUpdateMobEffectPacketMixin", - "network.ServerGamePacketListenerImplMixin" - ], - "client": [ - "access.RenderStateShardAccessor", - "client.LightTextureMixin", - "client.LocalPlayerMixin", - "client.ModelPartMixin", - "client.PartDefinitionMixin", - "network.ClientPacketListenerMixin", - "network.MultiPlayerGameModeMixin" - ], - "injectors": { - "defaultRequire": 1 - } + "required": true, + "minVersion": "0.8", + "package": "com.cursedcauldron.wildbackport.core.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "access.ActivityAccessor", + "access.AxeItemAccessor", + "access.BooleanValueAccessor", + "access.CriteriaTriggersAccessor", + "access.DamageSourceAccessor", + "access.DoorBlockAccessor", + "access.FireBlockAccessor", + "access.GameRulesAccessor", + "access.MemoryModuleTypeAccessor", + "access.MobEffectAccessor", + "access.ModelPartAccessor", + "access.OverworldBiomesAccessor", + "access.PointedDripstoneBlockAccessor", + "access.PressurePlateBlockAccessor", + "access.RecordItemAccessor", + "access.RenderTypeAccessor", + "access.SensorTypeAccessor", + "access.SheetsAccessor", + "access.SimpleParticleTypeAccessor", + "access.StairBlockAccessor", + "access.StructureFeatureAccessor", + "access.StructureTemplatePoolAccessor", + "access.TrapDoorBlockAccessor", + "access.TreeDecoratorTypeAccessor", + "access.TreeFeatureAccessor", + "access.TrunkPlacerTypeAccessor", + "access.WalkNodeEvaluatorAccessor", + "access.WoodButtonBlockAccessor", + "access.WoodTypeAccessor", + "common.ItemsMixin", + "common.BlockEntityTypeMixin", + "common.FlyNodeEvaluatorMixin", + "common.LivingEntityMixin", + "common.MobEffectMixin", + "common.MobEffectMixin$MobEffectInstanceMixin", + "common.NoteBlockMixin", + "common.PathfinderMobMixin", + "common.PlayerMixin", + "common.PointedDripstoneBlockMixin", + "common.SculkSensorBlockEntityMixin", + "common.SculkSensorBlockMixin", + "common.ServerPlayerMixin", + "common.SlimeMixin", + "common.VibrationListenerMixin", + "extension.BoatTypeMixin", + "extension.PoseMixin", + "network.ClientboundUpdateMobEffectPacketMixin", + "network.ServerGamePacketListenerImplMixin" + ], + "client": [ + "access.RenderStateShardAccessor", + "client.LightTextureMixin", + "client.LocalPlayerMixin", + "client.ModelPartMixin", + "client.PartDefinitionMixin", + "network.ClientPacketListenerMixin", + "network.MultiPlayerGameModeMixin" + ], + "injectors": { + "defaultRequire": 1 + } } diff --git a/common/src/main/resources/wildbackport.accesswidener b/common/src/main/resources/wildbackport.accesswidener index ae57ca0..d7e9af2 100644 --- a/common/src/main/resources/wildbackport.accesswidener +++ b/common/src/main/resources/wildbackport.accesswidener @@ -25,5 +25,4 @@ transitive-accessible method net/minecraft/client/particle/HugeExplosionParticle transitive-accessible method net/minecraft/world/level/block/MultifaceBlock hasFace (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;)Z transitive-accessible method net/minecraft/core/Registry registerSimple (Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/core/Registry$RegistryBootstrap;)Lnet/minecraft/core/Registry; -# Doesn't work and not needed? -#transitive-accessible method net/minecraft/client/renderer/item/ItemProperties register (Lnet/minecraft/world/item/Item;Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/renderer/item/ClampedItemPropertyFunction;)V +transitive-accessible method net/minecraft/client/renderer/item/ItemProperties register (Lnet/minecraft/world/item/Item;Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/renderer/item/ClampedItemPropertyFunction;)V