Implement custom data tracker

This commit is contained in:
Sollace 2024-05-20 20:56:44 +01:00
parent 9f407dfb76
commit f8f60a8d3d
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
24 changed files with 512 additions and 176 deletions

View file

@ -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<Race> REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID);
public static final Registry<Race> COMMAND_REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race/grantable"), DEFAULT_ID);
public static final PacketCodec<Race> PACKET_CODEC = PacketCodec.ofRegistry(REGISTRY);
public static final RegistryKey<? extends Registry<Race>> REGISTRY_KEY = REGISTRY.getKey();
private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("commands.race.fail", id));
private static final Function<Race, Composite> COMPOSITES = Util.memoize(race -> new Composite(race, null, null));

View file

@ -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<T extends Spell> extends Predicate<Spell> {
SpellPredicate<?> ALL = spell -> true;
SpellPredicate<IllusionarySpell> CAN_SUPPRESS = s -> s instanceof IllusionarySpell;
SpellPredicate<PlaceableSpell> IS_PLACED = s -> s instanceof PlaceableSpell;
SpellPredicate<AbstractDisguiseSpell> IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell;

View file

@ -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<Spell> {
AllSpells INSTANCE = spell -> true;
}

View file

@ -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()))),

View file

@ -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<LivingEntity> implements WeaklyOwned.Mutable<LivingEntity> {
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
private static final TrackedData<NbtCompound> MASTER = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
public static final TrackedData<Float> GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Integer> EATING = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final TrackedData<Boolean> DISCORDED = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
private static final TrackedData<Boolean> SMITTEN = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
static final TrackedData<NbtCompound> EFFECT = net.minecraft.entity.data.DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
public static void boostrap() {}
private final EntityPhysics<LivingEntity> physics;
@ -69,26 +65,27 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
.isEmpty();
});
protected final DataTracker.Entry<NbtCompound> master;
protected final DataTracker.Entry<Integer> eating;
protected final DataTracker.Entry<Boolean> discorded;
protected final DataTracker.Entry<Boolean> 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<LivingEntity> 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<LivingEntity> implements WeaklyOwned.Mutabl
@Override
public EntityReference<LivingEntity> 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<LivingEntity> 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<LivingEntity> 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);

View file

@ -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<T extends Entity> implements Physics, Copyable<EntityPhysics<T>>, Tickable {
private final TrackedData<Float> gravity;
protected final T entity;
private float lastGravity = 1;
public EntityPhysics(T entity, TrackedData<Float> gravity) {
private final DataTracker tracker;
protected final DataTracker.Entry<Float> 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<T extends Entity> implements Physics, Copyable<Entity
@Override
public void setBaseGravityModifier(float constant) {
entity.getDataTracker().set(gravity, constant);
tracker.set(gravity, constant);
}
@Override
public float getBaseGravityModifier() {
return entity.getDataTracker().get(gravity);
return tracker.get(gravity);
}
@Override

View file

@ -5,16 +5,16 @@ import java.util.List;
import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
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.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.*;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.decoration.ItemFrameEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
@ -29,24 +29,26 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random;
public class ItemImpl implements Equine<ItemEntity> {
private static final TrackedData<String> ITEM_RACE = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.STRING);
static final TrackedData<Float> 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> 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<ItemEntity> {
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<ItemEntity> {
@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<ItemEntity> {
@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);
}

View file

@ -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<ItemEntity> {
public ItemPhysics(ItemEntity entity) {
super(entity, ItemImpl.ITEM_GRAVITY);
public ItemPhysics(ItemEntity entity, DataTracker tracker) {
super(entity, tracker);
}
@Override

View file

@ -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<T extends LivingEntity> implements Equine<T>, Caster<T>, Transmittable {
private static final TrackedData<Optional<UUID>> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
//private static final TrackedData<Optional<UUID>> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
protected final T entity;
@ -99,19 +104,26 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
private final ItemTracker armour = addTicker(new ItemTracker(this));
private final Transportation<T> transportation = new Transportation<>(this);
protected Living(T entity, TrackedData<NbtCompound> effect) {
private final DataTrackerManager trackers;
protected final DataTracker tracker;
protected final DataTracker.Entry<UUID> 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 extends Tickable> Q addTicker(Q tickable) {
@ -166,15 +178,16 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
}
public Optional<UUID> 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

View file

@ -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<CastSpellEntity>, WeaklyOwned.Mutable<LivingEntity>, MagicImmune {
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
private final EntityPhysics<CastSpellEntity> physics = new EntityPhysics<>(this, GRAVITY);
private final EntityPhysics<CastSpellEntity> physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker());
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);

View file

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

View file

@ -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<Float> 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<Float> marker;
private final DataTracker tracker;
private final DataTracker.Entry<Float> marker;
private final float max;
private float trailingValue;
private float prevTrailingValue;
private float prevValue;
BarInst(TrackedData<Float> 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) {

View file

@ -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<Integer> dataEntry;
private final DataTracker tracker;
private final DataTracker.Entry<Integer> dataEntry;
private final boolean upgradeMana;
private final SoundEvent levelUpSound;
PlayerLevelStore(Pony pony, TrackedData<Integer> 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()));
}
}

View file

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

View file

@ -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<PlayerEntity> implements Copyable<Pony>, UpdateCallback {
private static final TrackedData<String> RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING);
private static final TrackedData<String> SUPPRESSED_RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING);
static final TrackedData<Float> ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Float> EXHAUSTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Float> EXERTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Float> MANA = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Float> XP = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Float> CHARGE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Integer> LEVEL = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER);
static final TrackedData<Integer> CORRUPTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER);
static final int INITIAL_SUN_IMMUNITY = 20;
private static final TrackedData<NbtCompound> 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<String, Integer> advancementProgress = new HashMap<>();
@ -121,11 +106,16 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
private int animationMaxDuration;
private int animationDuration;
private DataTracker.Entry<Race> race;
private DataTracker.Entry<Race> 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<PlayerEntity> implements Copyable<Pony>, 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<PlayerEntity> implements Copyable<Pony>, 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<PlayerEntity> implements Copyable<Pony>, 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<PlayerEntity> implements Copyable<Pony>, 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<PlayerEntity> implements Copyable<Pony>, Update
}
public Race getSuppressedRace() {
return Race.fromName(entity.getDataTracker().get(SUPPRESSED_RACE), Race.UNSET);
return tracker.get(suppressedRace);
}
public TraitDiscovery getDiscoveries() {

View file

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

View file

@ -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<MsgServerResources> SERVER_RESOURCES = SimpleNetworking.serverToClient(Unicopia.id("resources"), MsgServerResources::new);
S2CPacketType<MsgTrackedValues> SERVER_TRACKED_ENTITY_DATA = SimpleNetworking.serverToClient(Unicopia.id("tracked_entity_date"), MsgTrackedValues::new);
S2CPacketType<MsgOtherPlayerCapabilities> SERVER_OTHER_PLAYER_CAPABILITIES = SimpleNetworking.serverToClient(Unicopia.id("other_player_capabilities"), MsgOtherPlayerCapabilities::new);
S2CPacketType<MsgPlayerAnimationChange> SERVER_PLAYER_ANIMATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("other_player_animation_change"), MsgPlayerAnimationChange::new);
S2CPacketType<MsgSkyAngle> SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new);

View file

@ -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<Pair<?>> codecs = new ObjectArrayList<>();
private final Int2ObjectOpenHashMap<Consumer<?>> loadCallbacks = new Int2ObjectOpenHashMap<>();
private final Int2ObjectOpenHashMap<Runnable> 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 <T> Entry<T> startTracking(TrackableDataType<T> type, T initialValue) {
Entry<T> entry = new Entry<>(codecs.size());
codecs.add(new Pair<>(entry.id(), type, initialValue));
return entry;
}
public <T> void onReceive(Entry<T> entry, Consumer<T> loadCallback) {
loadCallbacks.put(entry.id(), loadCallback);
}
public <T> void onBeforeSend(Entry<T> entry, Runnable action) {
writethroughCallback.put(entry.id(), action);
}
@SuppressWarnings("unchecked")
private <T> Pair<T> getPair(Entry<T> entry) {
return (Pair<T>)codecs.get(entry.id());
}
public <T> T get(Entry<T> entry) {
return getPair(entry).value;
}
public <T> void set(Entry<T> entry, T value) {
if (manager.isClient) {
return;
}
Pair<T> 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<Pair<?>> 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<Pair<?>> values) {
if (wipe) {
codecs.clear();
codecs.addAll(values);
for (var value : values) {
Consumer<?> callback = loadCallbacks.get(value.id);
if (callback != null) {
((Consumer<Object>)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<Object>)callback).accept(value.value);
}
}
}
});
}
}
public void close() {
manager.closeTracker(id);
}
public record Entry<T>(int id) {}
static class Pair<T> {
private final TrackableDataType<T> type;
public final int id;
public T value;
public Pair(int id, TrackableDataType<T> 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);
}
}
}

View file

@ -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<DataTracker> 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<MsgTrackedValues.TrackerEntries> 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());
}
}
}
}

View file

@ -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<TrackerEntries> updatedTrackers,
int[] removedTrackers
) implements HandledPacket<PlayerEntity> {
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<DataTracker.Pair<?>> 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));
}
}
}

View file

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

View file

@ -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<T>(int id, PacketCodec<T> codec) {
private static final List<TrackableDataType<?>> REGISTRY = new ArrayList<>();
private static final Interner<TrackableDataType<?>> INTERNER = Interners.newStrongInterner();
@SuppressWarnings("unchecked")
public static <T> TrackableDataType<T> of(int id) {
return (TrackableDataType<T>)REGISTRY.get(id);
}
public static <T> TrackableDataType<T> of(PacketCodec<T> codec) {
@SuppressWarnings("unchecked")
TrackableDataType<T> type = (TrackableDataType<T>) 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);
}
}

View file

@ -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<MagicBeamEntity>, MagicImmune {
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Boolean> HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
private static final TrackedData<Boolean> HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this, GRAVITY);
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this, Trackable.of(this).getDataTrackers().getPrimaryTracker());
public MagicBeamEntity(EntityType<MagicBeamEntity> type, World world) {
super(type, world);
@ -55,10 +54,10 @@ public class MagicBeamEntity extends MagicProjectileEntity implements Caster<Mag
@Override
protected void initDataTracker() {
super.initDataTracker();
getDataTracker().startTracking(GRAVITY, 1F);
getDataTracker().startTracking(HYDROPHOBIC, false);
getDataTracker().startTracking(EFFECT, new NbtCompound());
}
@Override
public void tick() {
super.tick();

View file

@ -1,25 +1,36 @@
package com.minelittlepony.unicopia.util.serialization;
import java.util.Optional;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public record PacketCodec<T>(PacketByteBuf.PacketReader<T> reader, PacketByteBuf.PacketWriter<T> writer) {
public static final PacketCodec<Boolean> BOOLEAN = new PacketCodec<>(PacketByteBuf::readBoolean, PacketByteBuf::writeBoolean);
public static final PacketCodec<Float> FLOAT = new PacketCodec<>(PacketByteBuf::readFloat, PacketByteBuf::writeFloat);
public static final PacketCodec<Integer> INT = new PacketCodec<>(PacketByteBuf::readInt, PacketByteBuf::writeInt);
public static final PacketCodec<Byte> BYTE = new PacketCodec<>(PacketByteBuf::readByte, (b, v) -> b.writeByte(v));
public static final PacketCodec<Long> LONG = new PacketCodec<>(PacketByteBuf::readLong, PacketByteBuf::writeLong);
public static final PacketCodec<String> STRING = new PacketCodec<>(PacketByteBuf::readString, PacketByteBuf::writeString);
public static final PacketCodec<UUID> UUID = new PacketCodec<>(PacketByteBuf::readUuid, PacketByteBuf::writeUuid);
public static final PacketCodec<Optional<UUID>> OPTIONAL_UUID = UUID.asOptional();
public static final PacketCodec<Identifier> IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString);
public static final PacketCodec<NbtCompound> NBT = new PacketCodec<>(PacketByteBuf::readNbt, PacketByteBuf::writeNbt);
public static final PacketCodec<BlockPos> POS = new PacketCodec<>(PacketByteBuf::readBlockPos, PacketByteBuf::writeBlockPos);
public static final PacketCodec<Optional<BlockPos>> OPTIONAL_POS = POS.asOptional();
public static final <T> PacketCodec<T> ofRegistry(Registry<T> registry) {
return INT.xMap(registry::get, registry::getRawId);
}