feat: implement recovery compass

This commit is contained in:
LordMZTE 2023-10-06 17:53:40 +02:00
parent 87e0233696
commit 4cad6de484
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
8 changed files with 273 additions and 88 deletions

View file

@ -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;
})
);
}
}

View file

@ -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<GlobalPos> {
public static final GlobalPosEntityDataSerializer INSTANCE
= new GlobalPosEntityDataSerializer();
public static final OptionalEntityDataSerializer<GlobalPos>
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());
}
}

View file

@ -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<T>
implements EntityDataSerializer<Optional<T>> {
final EntityDataSerializer<T> inner;
public OptionalEntityDataSerializer(EntityDataSerializer<T> inner) {
this.inner = inner;
}
@Override
public Optional<T> copy(Optional<T> object) {
return object.map(this.inner::copy);
}
@Override
public Optional<T> read(FriendlyByteBuf fbb) {
return fbb.readBoolean() ? Optional.of(this.inner.read(fbb)) : Optional.empty();
}
@Override
public void write(FriendlyByteBuf fbb, Optional<T> object) {
fbb.writeBoolean(object.isPresent());
object.ifPresent(innerObj -> this.inner.write(fbb, innerObj));
}
}

View file

@ -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<Optional<GlobalPos>>
DATA_LAST_DEATH_LOCATION_ID = SynchedEntityData.defineId(
Player.class, GlobalPosEntityDataSerializer.OPTIONAL_INSTANCE
);
protected PlayerMixin(EntityType<? extends LivingEntity> entityType, Level level) {
super(entityType, level);
throw new AssertionError();
}
@Unique
private WardenSpawnTracker spawnTracker;
@Unique
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
@Inject(method = "<init>", 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<GlobalPos> getLastDeathLocation() {
return this.lastDeathLocation;
return this.entityData.get(DATA_LAST_DEATH_LOCATION_ID);
}
@Override
public void setLastDeathLocation(Optional<GlobalPos> location) {
this.lastDeathLocation = location;
this.entityData.set(DATA_LAST_DEATH_LOCATION_ID, location);
}
}
}

View file

@ -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());
}
}

View file

@ -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"
}
}

View file

@ -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
}
}

View file

@ -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