diff --git a/src/main/java/com/minelittlepony/unicopia/Race.java b/src/main/java/com/minelittlepony/unicopia/Race.java index 90644373..2380c241 100644 --- a/src/main/java/com/minelittlepony/unicopia/Race.java +++ b/src/main/java/com/minelittlepony/unicopia/Race.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Ability; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.util.RegistryUtils; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; @@ -44,6 +45,7 @@ public record Race ( public static final String DEFAULT_ID = "unicopia:unset"; public static final Registry REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID); public static final Registry COMMAND_REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race/grantable"), DEFAULT_ID); + public static final PacketCodec PACKET_CODEC = PacketCodec.ofRegistry(REGISTRY); public static final RegistryKey> REGISTRY_KEY = REGISTRY.getKey(); private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("commands.race.fail", id)); private static final Function COMPOSITES = Util.memoize(race -> new Composite(race, null, null)); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java index 3a7213c7..358c4fb6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java @@ -7,10 +7,10 @@ import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.effect.MimicSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.ShieldSpell; - import net.minecraft.entity.Entity; public interface SpellPredicate extends Predicate { + SpellPredicate ALL = spell -> true; SpellPredicate CAN_SUPPRESS = s -> s instanceof IllusionarySpell; SpellPredicate IS_PLACED = s -> s instanceof PlaceableSpell; SpellPredicate IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/AllSpells.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/AllSpells.java deleted file mode 100644 index c6c5c2ff..00000000 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/AllSpells.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.minelittlepony.unicopia.client.render.spell; - -import com.minelittlepony.unicopia.ability.magic.SpellPredicate; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; - -public interface AllSpells extends SpellPredicate { - AllSpells INSTANCE = spell -> true; -} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index 90bfbbb2..4c78034a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.Living; @@ -124,7 +125,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader caster.asEntity().getDisplayName().copy().append(" (" + Registries.ENTITY_TYPE.getId(caster.asEntity().getType()) + ")"), caster.getMaster() != null ? Text.literal("Master: ").append(caster.getMaster().getDisplayName()) : Text.empty() ), - caster.getSpellSlot().stream(AllSpells.INSTANCE, false).flatMap(spell -> + caster.getSpellSlot().stream(SpellPredicate.ALL, false).flatMap(spell -> Stream.of( Text.literal("UUID: " + spell.getUuid()), Text.literal("|>Type: ").append(Text.literal(spell.getTypeAndTraits().type().getId().toString()).styled(s -> s.withColor(spell.getTypeAndTraits().type().getColor()))), diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index 40d90e32..46453917 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -21,6 +21,9 @@ import com.minelittlepony.unicopia.entity.ai.PrioritizedActiveTargetGoal; import com.minelittlepony.unicopia.entity.ai.TargettingUtil; import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; @@ -28,7 +31,6 @@ import net.minecraft.entity.SpawnGroup; import net.minecraft.entity.ai.goal.*; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.EntityAttributes; -import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.mob.*; @@ -39,13 +41,7 @@ import net.minecraft.nbt.NbtElement; import net.minecraft.util.math.MathHelper; public class Creature extends Living implements WeaklyOwned.Mutable { - private static final TrackedData EFFECT = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); - private static final TrackedData MASTER = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); - public static final TrackedData GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT); - private static final TrackedData EATING = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.INTEGER); - private static final TrackedData DISCORDED = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN); - private static final TrackedData SMITTEN = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN); - + static final TrackedData EFFECT = net.minecraft.entity.data.DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); public static void boostrap() {} private final EntityPhysics physics; @@ -69,26 +65,27 @@ public class Creature extends Living implements WeaklyOwned.Mutabl .isEmpty(); }); + protected final DataTracker.Entry master; + protected final DataTracker.Entry eating; + protected final DataTracker.Entry discorded; + protected final DataTracker.Entry smitten; + public Creature(LivingEntity entity) { - super(entity, EFFECT); - physics = new EntityPhysics<>(entity, GRAVITY); + super(entity); + physics = new EntityPhysics<>(entity, tracker); addTicker(physics); addTicker(this::updateConsumption); - } - @Override - public void initDataTracker() { - super.initDataTracker(); - entity.getDataTracker().startTracking(MASTER, owner.toNBT()); - entity.getDataTracker().startTracking(EATING, 0); - entity.getDataTracker().startTracking(DISCORDED, false); - entity.getDataTracker().startTracking(SMITTEN, false); + master = tracker.startTracking(TrackableDataType.of(PacketCodec.NBT), owner.toNBT()); + eating = tracker.startTracking(TrackableDataType.of(PacketCodec.INT), 0); + discorded = tracker.startTracking(TrackableDataType.of(PacketCodec.BOOLEAN), false); + smitten = tracker.startTracking(TrackableDataType.of(PacketCodec.BOOLEAN), false); } @Override public void setMaster(LivingEntity owner) { this.owner.set(owner); - entity.getDataTracker().set(MASTER, this.owner.toNBT()); + tracker.set(master, this.owner.toNBT()); if (owner != null) { targets.ifPresent(this::initMinionAi); } @@ -99,20 +96,20 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } public boolean isDiscorded() { - return entity.getDataTracker().get(DISCORDED); + return tracker.get(this.discorded); } public boolean isSmitten() { - return entity.getDataTracker().get(SMITTEN); + return tracker.get(this.smitten); } public void setSmitten(boolean smitten) { smittenTicks = smitten ? 20 : 0; - entity.getDataTracker().set(SMITTEN, smitten); + tracker.set(this.smitten, smitten); } public void setDiscorded(boolean discorded) { - entity.getDataTracker().set(DISCORDED, discorded); + tracker.set(this.discorded, discorded); discordedChanged = true; } @@ -124,9 +121,8 @@ public class Creature extends Living implements WeaklyOwned.Mutabl @Override public EntityReference getMasterReference() { - if (entity.getDataTracker().containsKey(MASTER)) { - NbtCompound data = entity.getDataTracker().get(MASTER); - owner.fromNBT(data); + if (master != null) { + owner.fromNBT(tracker.get(master)); } return owner; } @@ -239,10 +235,10 @@ public class Creature extends Living implements WeaklyOwned.Mutabl private void updateConsumption() { if (isClient()) { - eatTimer = entity.getDataTracker().get(EATING); + eatTimer = tracker.get(eating); } else if (eatMuffinGoal != null) { eatTimer = eatMuffinGoal.getTimer(); - entity.getDataTracker().set(EATING, eatTimer); + tracker.set(eating, eatTimer); } } @@ -331,8 +327,8 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } if (compound.contains("master", NbtElement.COMPOUND_TYPE)) { owner.fromNBT(compound.getCompound("master")); - if (entity.getDataTracker().containsKey(MASTER)) { - entity.getDataTracker().set(MASTER, owner.toNBT()); + if (master != null) { + tracker.set(master, owner.toNBT()); } if (owner.isSet()) { targets.ifPresent(this::initMinionAi); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java index 749ee3cf..2aba94c8 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java @@ -1,14 +1,16 @@ package com.minelittlepony.unicopia.entity; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.Tickable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import net.minecraft.block.BlockState; import net.minecraft.block.FenceGateBlock; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.mob.MobEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.registry.tag.BlockTags; @@ -18,15 +20,18 @@ import net.minecraft.util.math.Vec3d; public class EntityPhysics implements Physics, Copyable>, Tickable { - private final TrackedData gravity; - protected final T entity; private float lastGravity = 1; - public EntityPhysics(T entity, TrackedData gravity) { + private final DataTracker tracker; + protected final DataTracker.Entry gravity; + + public EntityPhysics(T entity, DataTracker tracker) { this.entity = entity; - this.gravity = gravity; + this.tracker = tracker; + //this.gravity = gravity; + gravity = tracker.startTracking(TrackableDataType.of(PacketCodec.FLOAT), 1F); } @Override @@ -91,12 +96,12 @@ public class EntityPhysics implements Physics, Copyable { - private static final TrackedData ITEM_RACE = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.STRING); - static final TrackedData ITEM_GRAVITY = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.FLOAT); - private final ItemEntity entity; private final ItemPhysics physics; - private Race serverRace; + private final DataTrackerManager trackers; + protected final DataTracker tracker; + + private final DataTracker.Entry race; public ItemImpl(ItemEntity owner) { this.entity = owner; - this.physics = new ItemPhysics(owner); + this.trackers = Trackable.of(entity).getDataTrackers(); + this.tracker = trackers.getPrimaryTracker(); + this.physics = new ItemPhysics(owner, tracker); + + race = tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); } @Override public void initDataTracker() { - entity.getDataTracker().startTracking(ITEM_GRAVITY, 1F); - entity.getDataTracker().startTracking(ITEM_RACE, Race.REGISTRY.getId(Race.HUMAN).toString()); } @Override @@ -58,13 +60,6 @@ public class ItemImpl implements Equine { public boolean beforeUpdate() { if (!entity.getWorld().isClient) { - Race race = getSpecies(); - if (race != serverRace) { - serverRace = race; - setSpecies(Race.HUMAN); - setSpecies(race); - } - if (WantItNeedItEnchantment.getLevel(entity) > 0) { var random = entity.getWorld().random; @@ -150,12 +145,12 @@ public class ItemImpl implements Equine { @Override public Race getSpecies() { - return Race.fromName(entity.getDataTracker().get(ITEM_RACE), Race.HUMAN); + return tracker.get(race); } @Override public void setSpecies(Race race) { - entity.getDataTracker().set(ITEM_RACE, Race.REGISTRY.getId(race).toString()); + tracker.set(this.race, race); } @Override @@ -165,7 +160,7 @@ public class ItemImpl implements Equine { @Override public void toNBT(NbtCompound compound) { - compound.putString("owner_race", Race.REGISTRY.getId(getSpecies()).toString()); + compound.putString("owner_race", getSpecies().getId().toString()); physics.toNBT(compound); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java index b747dd0a..04b5425d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemPhysics.java @@ -1,10 +1,12 @@ package com.minelittlepony.unicopia.entity; +import com.minelittlepony.unicopia.network.track.DataTracker; + import net.minecraft.entity.ItemEntity; class ItemPhysics extends EntityPhysics { - public ItemPhysics(ItemEntity entity) { - super(entity, ItemImpl.ITEM_GRAVITY); + public ItemPhysics(ItemEntity entity, DataTracker tracker) { + super(entity, tracker); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index fa8cf61d..407608f1 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -32,10 +32,15 @@ import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.network.datasync.EffectSync; import com.minelittlepony.unicopia.network.datasync.Transmittable; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.DataTrackerManager; +import com.minelittlepony.unicopia.network.track.Trackable; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.projectile.ProjectileImpactListener; import com.minelittlepony.unicopia.server.world.DragonBreathStore; import com.minelittlepony.unicopia.util.*; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import it.unimi.dsi.fastutil.floats.Float2ObjectFunction; import net.fabricmc.fabric.api.util.TriState; @@ -48,7 +53,6 @@ import net.minecraft.entity.attribute.EntityAttributeInstance; import net.minecraft.entity.attribute.EntityAttributeModifier; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageTypes; -import net.minecraft.entity.data.*; import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.ProjectileEntity; @@ -64,6 +68,7 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.util.Hand; +import net.minecraft.util.Util; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -71,7 +76,7 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public abstract class Living implements Equine, Caster, Transmittable { - private static final TrackedData> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID); + //private static final TrackedData> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID); protected final T entity; @@ -99,19 +104,26 @@ public abstract class Living implements Equine, Caste private final ItemTracker armour = addTicker(new ItemTracker(this)); private final Transportation transportation = new Transportation<>(this); - protected Living(T entity, TrackedData effect) { + private final DataTrackerManager trackers; + protected final DataTracker tracker; + + protected final DataTracker.Entry carrierId; + + protected Living(T entity) { this.entity = entity; - this.effectDelegate = new EffectSync(this, effect); + this.trackers = Trackable.of(entity).getDataTrackers(); + this.tracker = trackers.getPrimaryTracker(); + this.effectDelegate = new EffectSync(this, Creature.EFFECT); this.sneakingHeuristic = addTicker(new Interactable(entity::isSneaking)); this.landedHeuristic = addTicker(new Interactable(entity::isOnGround)); this.jumpingHeuristic = addTicker(new Interactable(((LivingEntityDuck)entity)::isJumping)); + + carrierId = tracker.startTracking(TrackableDataType.of(PacketCodec.UUID), Util.NIL_UUID); } @Override public void initDataTracker() { - effectDelegate.initDataTracker(); - entity.getDataTracker().startTracking(Creature.GRAVITY, 1F); - entity.getDataTracker().startTracking(CARRIER_ID, Optional.empty()); + entity.getDataTracker().startTracking(Creature.EFFECT, new NbtCompound()); } public Q addTicker(Q tickable) { @@ -166,15 +178,16 @@ public abstract class Living implements Equine, Caste } public Optional getCarrierId() { - return entity.getDataTracker().get(CARRIER_ID); + UUID carrierId = tracker.get(this.carrierId); + return carrierId == Util.NIL_UUID ? Optional.empty() : Optional.of(carrierId); } public void setCarrier(UUID carrier) { - entity.getDataTracker().set(CARRIER_ID, Optional.ofNullable(carrier)); + tracker.set(this.carrierId, carrier == null ? Util.NIL_UUID : carrier); } public void setCarrier(Entity carrier) { - entity.getDataTracker().set(CARRIER_ID, Optional.ofNullable(carrier).map(Entity::getUuid)); + setCarrier(carrier == null ? Util.NIL_UUID : carrier.getUuid()); } @Nullable diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index 92b1a909..649bb5d5 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.network.datasync.EffectSync; +import com.minelittlepony.unicopia.network.track.Trackable; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityDimensions; @@ -26,10 +27,9 @@ import net.minecraft.text.Text; import net.minecraft.world.World; public class CastSpellEntity extends LightEmittingEntity implements Caster, WeaklyOwned.Mutable, MagicImmune { - private static final TrackedData GRAVITY = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.FLOAT); private static final TrackedData EFFECT = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); - private final EntityPhysics physics = new EntityPhysics<>(this, GRAVITY); + private final EntityPhysics physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); private final EffectSync effectDelegate = new EffectSync(this, EFFECT); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java index 37009bb5..75fadc1c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java @@ -8,15 +8,15 @@ import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; import com.minelittlepony.unicopia.entity.mob.StormCloudEntity; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.SideShapeType; -import net.minecraft.entity.data.DataTracker; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.registry.tag.BlockTags; @@ -28,8 +28,6 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Acrobatics implements Tickable, NbtSerialisable { - static final TrackedData> HANGING_POSITION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS); - private int ticksHanging; private Direction attachDirection; @@ -38,14 +36,15 @@ public class Acrobatics implements Tickable, NbtSerialisable { private final Pony pony; private final PlayerEntity entity; - public Acrobatics(Pony pony) { - this.pony = pony; - this.entity = pony.asEntity(); - pony.addTicker(this::checkDislodge); - } + private final DataTracker tracker; + private final DataTracker.Entry> hangingPos; - public void initDataTracker() { - entity.getDataTracker().startTracking(HANGING_POSITION, Optional.empty()); + public Acrobatics(Pony pony, DataTracker tracker) { + this.pony = pony; + this.tracker = tracker; + this.entity = pony.asEntity(); + this.hangingPos = tracker.startTracking(TrackableDataType.of(PacketCodec.OPTIONAL_POS), Optional.empty()); + pony.addTicker(this::checkDislodge); } public boolean isImmobile() { @@ -147,7 +146,7 @@ public class Acrobatics implements Tickable, NbtSerialisable { } public Optional getHangingPosition() { - return entity.getDataTracker().get(HANGING_POSITION); + return tracker.get(hangingPos); } public boolean isHanging() { @@ -155,13 +154,13 @@ public class Acrobatics implements Tickable, NbtSerialisable { } public void stopHanging() { - entity.getDataTracker().set(HANGING_POSITION, Optional.empty()); + tracker.set(hangingPos, Optional.empty()); entity.calculateDimensions(); ticksHanging = 0; } public void startHanging(BlockPos pos) { - entity.getDataTracker().set(HANGING_POSITION, Optional.of(pos)); + tracker.set(hangingPos, Optional.of(pos)); entity.teleport(pos.getX() + 0.5, pos.getY() - 1, pos.getZ() + 0.5); entity.setVelocity(Vec3d.ZERO); entity.setSneaking(false); @@ -202,6 +201,6 @@ public class Acrobatics implements Tickable, NbtSerialisable { @Override public void fromNBT(NbtCompound compound) { ticksHanging = compound.getInt("ticksHanging"); - pony.asEntity().getDataTracker().set(HANGING_POSITION, NbtSerialisable.BLOCK_POS.readOptional("hangingPosition", compound)); + tracker.set(hangingPos, NbtSerialisable.BLOCK_POS.readOptional("hangingPosition", compound)); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java b/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java index 511e333d..ccb7a65c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/ManaContainer.java @@ -3,11 +3,13 @@ package com.minelittlepony.unicopia.entity.player; import java.util.HashMap; import java.util.Map; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; -import net.minecraft.entity.data.TrackedData; import net.minecraft.nbt.NbtCompound; import net.minecraft.util.math.MathHelper; @@ -23,14 +25,14 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl private final BarInst xp; private final BarInst charge; - public ManaContainer(Pony pony) { + public ManaContainer(Pony pony, DataTracker tracker) { this.pony = pony; - this.energy = addBar("energy", new BarInst(Pony.ENERGY, 100F, 0)); - this.exhaustion = addBar("exhaustion", new BarInst(Pony.EXHAUSTION, 100F, 0)); - this.exertion = addBar("exertion", new BarInst(Pony.EXERTION, 10F, 0)); - this.xp = addBar("xp", new BarInst(Pony.XP, 1F, 0)); - this.mana = addBar("mana", new XpCollectingBar(Pony.MANA, 100F, 1)); - this.charge = addBar("charge", new BarInst(Pony.CHARGE, 10F, 0) { + this.energy = addBar("energy", new BarInst(tracker, 100F, 0)); + this.exhaustion = addBar("exhaustion", new BarInst(tracker, 100F, 0)); + this.exertion = addBar("exertion", new BarInst(tracker, 10F, 0)); + this.xp = addBar("xp", new BarInst(tracker, 1F, 0)); + this.mana = addBar("mana", new XpCollectingBar(tracker, 100F, 1)); + this.charge = addBar("charge", new BarInst(tracker, 10F, 0) { @Override protected float applyLimits(float value) { return Math.max(0, value); @@ -38,10 +40,6 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl }); } - public void initDataTracker() { - bars.values().forEach(BarInst::initDataTracker); - } - protected BarInst addBar(String name, BarInst bar) { bars.put(name, bar); return bar; @@ -130,9 +128,8 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl } class XpCollectingBar extends BarInst { - - XpCollectingBar(TrackedData marker, float max, float initial) { - super(marker, max, initial); + XpCollectingBar(DataTracker tracker, float max, float initial) { + super(tracker, max, initial); } @Override @@ -156,29 +153,26 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl } class BarInst implements Bar, NbtSerialisable { - - private final TrackedData marker; + private final DataTracker tracker; + private final DataTracker.Entry marker; private final float max; private float trailingValue; private float prevTrailingValue; private float prevValue; - BarInst(TrackedData marker, float max, float initial) { - this.marker = marker; + BarInst(DataTracker tracker, float max, float initial) { + this.tracker = tracker; this.max = max; this.trailingValue = initial; this.prevTrailingValue = initial; this.prevValue = initial; - } - - public void initDataTracker() { - pony.asEntity().getDataTracker().startTracking(marker, max * trailingValue); + this.marker = tracker.startTracking(TrackableDataType.of(PacketCodec.FLOAT), max * trailingValue); } @Override public float get() { - return applyLimits(pony.asEntity().getDataTracker().get(marker)); + return applyLimits(tracker.get(marker)); } @Override @@ -197,7 +191,7 @@ class ManaContainer implements MagicReserves, Tickable, NbtSerialisable, Copyabl } private void load(float value) { - pony.asEntity().getDataTracker().set(marker, value); + tracker.set(marker, value); } protected float getInitial(float initial) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java index f883529a..edd6f65f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerLevelStore.java @@ -1,8 +1,10 @@ package com.minelittlepony.unicopia.entity.player; import com.minelittlepony.unicopia.ability.magic.Levelled; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; -import net.minecraft.entity.data.TrackedData; import net.minecraft.sound.*; import net.minecraft.util.math.MathHelper; @@ -10,15 +12,17 @@ class PlayerLevelStore implements Levelled.LevelStore { private final Pony pony; - private final TrackedData dataEntry; + private final DataTracker tracker; + private final DataTracker.Entry dataEntry; private final boolean upgradeMana; private final SoundEvent levelUpSound; - PlayerLevelStore(Pony pony, TrackedData dataEntry, boolean upgradeMana, SoundEvent levelUpSound) { + PlayerLevelStore(Pony pony, DataTracker tracker, boolean upgradeMana, SoundEvent levelUpSound) { this.pony = pony; - this.dataEntry = dataEntry; + this.tracker = tracker; + this.dataEntry = tracker.startTracking(TrackableDataType.of(PacketCodec.INT), 0); this.upgradeMana = upgradeMana; this.levelUpSound = levelUpSound; } @@ -41,11 +45,11 @@ class PlayerLevelStore implements Levelled.LevelStore { @Override public int get() { - return pony.asEntity().getDataTracker().get(dataEntry); + return tracker.get(dataEntry); } @Override public void set(int level) { - pony.asEntity().getDataTracker().set(dataEntry, MathHelper.clamp(level, 0, getMax())); + tracker.set(dataEntry, MathHelper.clamp(level, 0, getMax())); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index cebc54c6..77ee72e0 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -25,6 +25,7 @@ import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.MsgPlayerFlightControlsInput; +import com.minelittlepony.unicopia.network.track.DataTracker; import com.minelittlepony.unicopia.particle.*; import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; @@ -97,8 +98,8 @@ public class PlayerPhysics extends EntityPhysics implements Tickab private Lerp updraft = new Lerp(0); private Lerp windStrength = new Lerp(0); - public PlayerPhysics(Pony pony) { - super(pony.asEntity(), Creature.GRAVITY); + public PlayerPhysics(Pony pony, DataTracker tracker) { + super(pony.asEntity(), tracker); this.pony = pony; dimensions = new PlayerDimensions(pony, this); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 87a8d8d9..82033249 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -34,6 +34,8 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.util.*; import com.minelittlepony.unicopia.network.*; import com.minelittlepony.unicopia.network.datasync.EffectSync.UpdateCallback; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.server.world.UGameRules; import com.minelittlepony.common.util.animation.LinearInterpolator; import com.google.common.collect.Streams; @@ -46,9 +48,6 @@ import net.minecraft.entity.*; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageTypes; -import net.minecraft.entity.data.DataTracker; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.player.PlayerEntity; @@ -71,28 +70,14 @@ import net.minecraft.world.GameMode; import net.minecraft.world.GameRules; public class Pony extends Living implements Copyable, UpdateCallback { - private static final TrackedData RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING); - private static final TrackedData SUPPRESSED_RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING); - - static final TrackedData ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData EXHAUSTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData EXERTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData MANA = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData XP = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData CHARGE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); - static final TrackedData LEVEL = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER); - static final TrackedData CORRUPTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER); - static final int INITIAL_SUN_IMMUNITY = 20; - private static final TrackedData EFFECT = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); - private final AbilityDispatcher powers = new AbilityDispatcher(this); - private final PlayerPhysics gravity = addTicker(new PlayerPhysics(this)); + private final PlayerPhysics gravity = addTicker(new PlayerPhysics(this, tracker)); private final PlayerCharmTracker charms = new PlayerCharmTracker(this); private final PlayerCamera camera = new PlayerCamera(this); private final TraitDiscovery discoveries = new TraitDiscovery(this); - private final Acrobatics acrobatics = new Acrobatics(this); + private final Acrobatics acrobatics = new Acrobatics(this, tracker); private final CorruptionHandler corruptionHandler = new CorruptionHandler(this); private final Map advancementProgress = new HashMap<>(); @@ -121,11 +106,16 @@ public class Pony extends Living implements Copyable, Update private int animationMaxDuration; private int animationDuration; + private DataTracker.Entry race; + private DataTracker.Entry suppressedRace; + public Pony(PlayerEntity player) { - super(player, EFFECT); - this.levels = new PlayerLevelStore(this, LEVEL, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); - this.corruption = new PlayerLevelStore(this, CORRUPTION, false, USounds.ENTITY_PLAYER_CORRUPTION); - this.mana = addTicker(new ManaContainer(this)); + super(player); + race = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); + suppressedRace = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); + this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); + this.corruption = new PlayerLevelStore(this, tracker, false, USounds.ENTITY_PLAYER_CORRUPTION); + this.mana = addTicker(new ManaContainer(this, tracker)); addTicker(this::updateAnimations); addTicker(this::updateBatPonyAbilities); @@ -134,17 +124,6 @@ public class Pony extends Living implements Copyable, Update addTicker(corruptionHandler); } - @Override - public void initDataTracker() { - super.initDataTracker(); - acrobatics.initDataTracker(); - mana.initDataTracker(); - entity.getDataTracker().startTracking(LEVEL, 0); - entity.getDataTracker().startTracking(CORRUPTION, 0); - entity.getDataTracker().startTracking(RACE, Race.DEFAULT_ID); - entity.getDataTracker().startTracking(SUPPRESSED_RACE, Race.DEFAULT_ID); - } - public static void registerAttributes(DefaultAttributeContainer.Builder builder) { builder.add(UEntityAttributes.EXTRA_MINING_SPEED); builder.add(UEntityAttributes.ENTITY_GRAVITY_MODIFIER); @@ -218,7 +197,7 @@ public class Pony extends Living implements Copyable, Update */ @Override public Race getSpecies() { - return Race.fromName(entity.getDataTracker().get(RACE), Race.HUMAN); + return tracker.get(race); } /** @@ -242,7 +221,7 @@ public class Pony extends Living implements Copyable, Update public void setSpecies(Race race) { race = race.validate(entity); Race current = getSpecies(); - entity.getDataTracker().set(RACE, race.getId().toString()); + tracker.set(this.race, race); if (race != current) { clearSuppressedRace(); } @@ -255,7 +234,7 @@ public class Pony extends Living implements Copyable, Update } public void setSuppressedRace(Race race) { - entity.getDataTracker().set(SUPPRESSED_RACE, race.validate(entity).getId().toString()); + tracker.set(suppressedRace, race.validate(entity)); } public void clearSuppressedRace() { @@ -263,7 +242,7 @@ public class Pony extends Living implements Copyable, Update } public Race getSuppressedRace() { - return Race.fromName(entity.getDataTracker().get(SUPPRESSED_RACE), Race.UNSET); + return tracker.get(suppressedRace); } public TraitDiscovery getDiscoveries() { diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java index 13644fbb..39740a41 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java @@ -11,6 +11,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.entity.duck.LavaAffine; +import com.minelittlepony.unicopia.network.track.DataTrackerManager; +import com.minelittlepony.unicopia.network.track.Trackable; import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.magic.Caster; @@ -19,11 +21,11 @@ import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.duck.EntityDuck; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.MovementType; import net.minecraft.entity.Entity.PositionUpdater; import net.minecraft.entity.Entity.RemovalReason; +import net.minecraft.entity.EntityType; import net.minecraft.fluid.Fluid; import net.minecraft.item.ItemStack; import net.minecraft.registry.tag.TagKey; @@ -31,10 +33,12 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @Mixin(Entity.class) -abstract class MixinEntity implements EntityDuck { +abstract class MixinEntity implements EntityDuck, Trackable { @Nullable private transient Caster host; + private DataTrackerManager dataTrackerManager; + @Override @Nullable public Caster getHost() { @@ -46,6 +50,14 @@ abstract class MixinEntity implements EntityDuck { this.host = host; } + @Override + public DataTrackerManager getDataTrackers() { + if (dataTrackerManager == null) { + dataTrackerManager = new DataTrackerManager((Entity)(Object)this); + } + return dataTrackerManager; + } + @Override @Accessor("submergedFluidTag") public abstract Set> getSubmergedFluidTags(); @@ -104,6 +116,13 @@ abstract class MixinEntity implements EntityDuck { } } + @Inject(method = "tick()V", at = @At("RETURN")) + private void afterTick(CallbackInfo info) { + if (dataTrackerManager != null) { + dataTrackerManager.tick(); + } + } + @Inject(method = "updatePassengerPosition(Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/Entity$PositionUpdater;)V", at = @At("HEAD"), cancellable = true diff --git a/src/main/java/com/minelittlepony/unicopia/network/Channel.java b/src/main/java/com/minelittlepony/unicopia/network/Channel.java index 8e6bc8c2..e9f86d0d 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/Channel.java +++ b/src/main/java/com/minelittlepony/unicopia/network/Channel.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.network; import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.network.track.MsgTrackedValues; import com.minelittlepony.unicopia.server.world.UnicopiaWorldProperties; import com.minelittlepony.unicopia.server.world.ZapAppleStageStore; import com.sollace.fabwork.api.packets.*; @@ -31,6 +32,7 @@ public interface Channel { S2CPacketType SERVER_RESOURCES = SimpleNetworking.serverToClient(Unicopia.id("resources"), MsgServerResources::new); + S2CPacketType SERVER_TRACKED_ENTITY_DATA = SimpleNetworking.serverToClient(Unicopia.id("tracked_entity_date"), MsgTrackedValues::new); S2CPacketType SERVER_OTHER_PLAYER_CAPABILITIES = SimpleNetworking.serverToClient(Unicopia.id("other_player_capabilities"), MsgOtherPlayerCapabilities::new); S2CPacketType SERVER_PLAYER_ANIMATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("other_player_animation_change"), MsgPlayerAnimationChange::new); S2CPacketType SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new); diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java new file mode 100644 index 00000000..71116e23 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTracker.java @@ -0,0 +1,143 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +import org.jetbrains.annotations.Nullable; + +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.network.PacketByteBuf; + +public class DataTracker { + private final List> codecs = new ObjectArrayList<>(); + private final Int2ObjectOpenHashMap> loadCallbacks = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectOpenHashMap writethroughCallback = new Int2ObjectOpenHashMap<>(); + private IntSet dirtyIndices = new IntOpenHashSet(); + + private final DataTrackerManager manager; + private boolean initial = true; + + final int id; + + public DataTracker(DataTrackerManager manager, int id) { + this.manager = manager; + this.id = id; + } + + public Entry startTracking(TrackableDataType type, T initialValue) { + Entry entry = new Entry<>(codecs.size()); + codecs.add(new Pair<>(entry.id(), type, initialValue)); + return entry; + } + + public void onReceive(Entry entry, Consumer loadCallback) { + loadCallbacks.put(entry.id(), loadCallback); + } + + public void onBeforeSend(Entry entry, Runnable action) { + writethroughCallback.put(entry.id(), action); + } + + @SuppressWarnings("unchecked") + private Pair getPair(Entry entry) { + return (Pair)codecs.get(entry.id()); + } + + public T get(Entry entry) { + return getPair(entry).value; + } + + public void set(Entry entry, T value) { + if (manager.isClient) { + return; + } + + Pair pair = getPair(entry); + if (!Objects.equals(pair.value, value)) { + pair.value = value; + dirtyIndices.add(entry.id()); + } + } + + @Nullable + MsgTrackedValues.TrackerEntries getDirtyPairs() { + writethroughCallback.values().forEach(Runnable::run); + + if (initial) { + initial = false; + dirtyIndices = new IntOpenHashSet(); + return new MsgTrackedValues.TrackerEntries(id, true, codecs); + } + + if (dirtyIndices.isEmpty()) { + return null; + } + + IntSet toSend = dirtyIndices; + dirtyIndices = new IntOpenHashSet(); + List> pairs = new ArrayList<>(); + for (int i : toSend) { + pairs.add(codecs.get(i)); + } + return new MsgTrackedValues.TrackerEntries(id, false, pairs); + } + + @SuppressWarnings("unchecked") + void load(boolean wipe, List> values) { + if (wipe) { + codecs.clear(); + codecs.addAll(values); + for (var value : values) { + Consumer callback = loadCallbacks.get(value.id); + if (callback != null) { + ((Consumer)callback).accept(value.value); + } + } + } else { + values.forEach(value -> { + if (value.id >= 0 && value.id < codecs.size()) { + if (codecs.get(value.id).type == value.type) { + codecs.set(value.id, value); + Consumer callback = loadCallbacks.get(value.id); + if (callback != null) { + ((Consumer)callback).accept(value.value); + } + } + } + }); + } + } + + public void close() { + manager.closeTracker(id); + } + + public record Entry(int id) {} + static class Pair { + private final TrackableDataType type; + public final int id; + public T value; + + public Pair(int id, TrackableDataType type, T value) { + this.id = id; + this.type = type; + this.value = value; + } + + public Pair(PacketByteBuf buffer) { + this.id = buffer.readInt(); + this.type = TrackableDataType.of(buffer.readInt()); + this.value = type.read(buffer); + } + + public void write(PacketByteBuf buffer) { + buffer.writeInt(id); + type.write(buffer, value); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java new file mode 100644 index 00000000..e4e9e01e --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/DataTrackerManager.java @@ -0,0 +1,83 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.ArrayList; +import java.util.List; + +import com.minelittlepony.unicopia.network.Channel; +import com.minelittlepony.unicopia.util.Tickable; + +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.entity.Entity; + +public class DataTrackerManager implements Tickable { + private final Entity entity; + final boolean isClient; + private final Int2ObjectOpenHashMap trackers = new Int2ObjectOpenHashMap<>(); + + private IntSet discardedTrackers = new IntOpenHashSet(); + private int nextId = 0; + + private final DataTracker primaryTracker = checkoutTracker(); + + public DataTrackerManager(Entity entity) { + this.entity = entity; + this.isClient = entity.getWorld().isClient; + } + + public DataTracker getPrimaryTracker() { + return primaryTracker; + } + + public DataTracker checkoutTracker() { + DataTracker tracker = new DataTracker(this, nextId++); + trackers.put(tracker.id, tracker); + return tracker; + } + + void closeTracker(int id) { + if (id <= 0) { + return; + } + + trackers.remove(id); + if (!isClient) { + discardedTrackers.add(id); + } + } + + @Override + public void tick() { + if (isClient) { + return; + } + + List toTransmit = new ArrayList<>(); + + for (var entry : trackers.int2ObjectEntrySet()) { + MsgTrackedValues.TrackerEntries dirtyPairs = entry.getValue().getDirtyPairs(); + if (dirtyPairs != null) { + toTransmit.add(dirtyPairs); + } + } + + if (!toTransmit.isEmpty() || !discardedTrackers.isEmpty()) { + MsgTrackedValues packet = new MsgTrackedValues(entity.getId(), toTransmit, discardedTrackers.toIntArray()); + discardedTrackers = new IntOpenHashSet(); + Channel.SERVER_TRACKED_ENTITY_DATA.sendToSurroundingPlayers(packet, entity); + } + } + + void load(MsgTrackedValues packet) { + for (int id : packet.removedTrackers()) { + closeTracker(id); + } + for (var update : packet.updatedTrackers()) { + DataTracker tracker = trackers.get(update.id()); + if (tracker != null) { + tracker.load(update.wipe(), update.values()); + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java new file mode 100644 index 00000000..7f8d16e4 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/MsgTrackedValues.java @@ -0,0 +1,46 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.ArrayList; +import java.util.List; +import com.sollace.fabwork.api.packets.HandledPacket; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; + +public record MsgTrackedValues( + int owner, + List updatedTrackers, + int[] removedTrackers +) implements HandledPacket { + public MsgTrackedValues(PacketByteBuf buffer) { + this(buffer.readInt(), buffer.readCollection(ArrayList::new, TrackerEntries::new), buffer.readIntArray()); + } + + @Override + public void toBuffer(PacketByteBuf buffer) { + buffer.writeInt(owner); + buffer.writeCollection(updatedTrackers, (buf, tracker) -> tracker.write(buf)); + buffer.writeIntArray(removedTrackers); + } + + @Override + public void handle(PlayerEntity sender) { + Entity entity = sender.getWorld().getEntityById(owner); + if (entity instanceof Trackable trackable) { + trackable.getDataTrackers().load(this); + } + } + + public record TrackerEntries(int id, boolean wipe, List> values) { + public TrackerEntries(PacketByteBuf buffer) { + this(buffer.readInt(), buffer.readBoolean(), buffer.readCollection(ArrayList::new, DataTracker.Pair::new)); + } + + public void write(PacketByteBuf buffer) { + buffer.writeInt(id); + buffer.writeBoolean(wipe); + buffer.writeCollection(values, (buf, pair) -> pair.write(buf)); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java b/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java new file mode 100644 index 00000000..5fdcd9a0 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/Trackable.java @@ -0,0 +1,12 @@ +package com.minelittlepony.unicopia.network.track; + +import net.minecraft.entity.Entity; + +public interface Trackable { + + DataTrackerManager getDataTrackers(); + + static Trackable of(Entity entity) { + return (Trackable)entity; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java new file mode 100644 index 00000000..6b4500a4 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java @@ -0,0 +1,38 @@ +package com.minelittlepony.unicopia.network.track; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.Interner; +import com.google.common.collect.Interners; +import com.minelittlepony.unicopia.util.serialization.PacketCodec; + +import net.minecraft.network.PacketByteBuf; + +public record TrackableDataType(int id, PacketCodec codec) { + private static final List> REGISTRY = new ArrayList<>(); + private static final Interner> INTERNER = Interners.newStrongInterner(); + + @SuppressWarnings("unchecked") + public static TrackableDataType of(int id) { + return (TrackableDataType)REGISTRY.get(id); + } + + public static TrackableDataType of(PacketCodec codec) { + @SuppressWarnings("unchecked") + TrackableDataType type = (TrackableDataType) INTERNER.intern(new TrackableDataType<>(REGISTRY.size(), codec)); + if (type.id() == REGISTRY.size()) { + REGISTRY.add(type); + } + return type; + } + + public T read(PacketByteBuf buffer) { + return codec().read(buffer); + } + + public void write(PacketByteBuf buffer, T value) { + buffer.writeInt(id()); + codec().write(buffer, value); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java index 1c1f9f44..daea0f24 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/MagicBeamEntity.java @@ -19,6 +19,7 @@ import com.minelittlepony.unicopia.entity.MagicImmune; import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.network.datasync.EffectSync; +import com.minelittlepony.unicopia.network.track.Trackable; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -31,13 +32,11 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class MagicBeamEntity extends MagicProjectileEntity implements Caster, MagicImmune { - private static final TrackedData GRAVITY = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.FLOAT); - private static final TrackedData HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN); private static final TrackedData EFFECT = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); + private static final TrackedData HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN); private final EffectSync effectDelegate = new EffectSync(this, EFFECT); - - private final EntityPhysics physics = new EntityPhysics<>(this, GRAVITY); + private final EntityPhysics physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker()); public MagicBeamEntity(EntityType type, World world) { super(type, world); @@ -55,10 +54,10 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster(PacketByteBuf.PacketReader reader, PacketByteBuf.PacketWriter writer) { + public static final PacketCodec BOOLEAN = new PacketCodec<>(PacketByteBuf::readBoolean, PacketByteBuf::writeBoolean); public static final PacketCodec FLOAT = new PacketCodec<>(PacketByteBuf::readFloat, PacketByteBuf::writeFloat); public static final PacketCodec INT = new PacketCodec<>(PacketByteBuf::readInt, PacketByteBuf::writeInt); public static final PacketCodec BYTE = new PacketCodec<>(PacketByteBuf::readByte, (b, v) -> b.writeByte(v)); public static final PacketCodec LONG = new PacketCodec<>(PacketByteBuf::readLong, PacketByteBuf::writeLong); public static final PacketCodec STRING = new PacketCodec<>(PacketByteBuf::readString, PacketByteBuf::writeString); + public static final PacketCodec UUID = new PacketCodec<>(PacketByteBuf::readUuid, PacketByteBuf::writeUuid); + public static final PacketCodec> OPTIONAL_UUID = UUID.asOptional(); public static final PacketCodec IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString); + public static final PacketCodec NBT = new PacketCodec<>(PacketByteBuf::readNbt, PacketByteBuf::writeNbt); + + public static final PacketCodec POS = new PacketCodec<>(PacketByteBuf::readBlockPos, PacketByteBuf::writeBlockPos); + public static final PacketCodec> OPTIONAL_POS = POS.asOptional(); + public static final PacketCodec ofRegistry(Registry registry) { return INT.xMap(registry::get, registry::getRawId); }