feat: implement recovery compass
This commit is contained in:
parent
87e0233696
commit
4cad6de484
|
@ -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;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue