From 238ca4bff72f4b676d72c85f7e92a53f73a96ff5 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 5 Aug 2023 17:39:56 +0100 Subject: [PATCH] Fixed faithful entities not remembering their owner after a save and reload. #136 --- .../magic/spell/effect/TargetSelecter.java | 22 +++-- .../render/PassThroughVertexConsumer.java | 98 +++++++++++++------ .../client/render/WorldRenderDelegate.java | 12 ++- .../unicopia/entity/Creature.java | 56 +++++++---- .../unicopia/entity/EntityReference.java | 4 + .../entity/FloatingArtefactEntity.java | 4 - 6 files changed, 133 insertions(+), 63 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java index 279599f2..209ec2d4 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java @@ -29,11 +29,8 @@ public class TargetSelecter { public Stream getEntities(Caster source, double radius, BiPredicate, Entity> filter) { targets.values().removeIf(Target::tick); - - Predicate ownerCheck = isOwnerOrFriend(spell, source); - return source.findAllEntitiesInRange(radius) - .filter(entity -> entity.isAlive() && !entity.isRemoved() && !ownerCheck.test(entity) && !SpellPredicate.IS_SHIELD_LIKE.isOn(entity)) + .filter(entity -> entity.isAlive() && !entity.isRemoved() && notOwnerOrFriend(spell, source, entity) && !SpellPredicate.IS_SHIELD_LIKE.isOn(entity)) .filter(entity -> !(entity instanceof SpellbookEntity)) .filter(e -> filter.test(source, e)) .map(i -> { @@ -47,19 +44,26 @@ public class TargetSelecter { } public static Predicate notOwnerOrFriend(Affine spell, Caster source) { - return TargetSelecter.isOwnerOrFriend(spell, source).negate(); + return target -> notOwnerOrFriend(spell, source, target); } public static Predicate isOwnerOrFriend(Affine spell, Caster source) { + return target -> isOwnerOrFriend(spell, source, target); + } + + public static boolean notOwnerOrFriend(Affine spell, Caster source, Entity target) { + return !isOwnerOrFriend(spell, source, target); + } + + public static boolean isOwnerOrFriend(Affine spell, Caster source, Entity target) { Entity owner = source.getMaster(); if (!(spell.isFriendlyTogether(source) && EquinePredicates.PLAYER_UNICORN.test(owner))) { - return e -> FriendshipBraceletItem.isComrade(source, e); + return FriendshipBraceletItem.isComrade(source, target); } - return entity -> { - return FriendshipBraceletItem.isComrade(source, entity) || (owner != null && (Pony.equal(entity, owner) || owner.isConnectedThroughVehicle(entity))); - }; + return FriendshipBraceletItem.isComrade(source, target) + || (owner != null && (Pony.equal(target, owner) || owner.isConnectedThroughVehicle(target))); } static final class Target { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/PassThroughVertexConsumer.java b/src/main/java/com/minelittlepony/unicopia/client/render/PassThroughVertexConsumer.java index 40df7b5c..b78ae93a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/PassThroughVertexConsumer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/PassThroughVertexConsumer.java @@ -6,52 +6,66 @@ import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumers; public class PassThroughVertexConsumer extends VertexConsumers.Union implements VertexConsumer { - private final Applicate colorFix; - private final Applicate textureFix; - private final Applicate overlayFix; - private final Applicate lightFix; + private final float[] buffer = new float[8]; + + private final Applicate colorFix; + private final Applicate textureFix; + private final Applicate overlayFix; private PassThroughVertexConsumer(VertexConsumer parent, Parameters parameters) { super(new VertexConsumer[] {parent}); - colorFix = Applicate.of(parameters.colorFix, (self, r, g, b, a) -> super.color(r, g, b, a)); - textureFix = Applicate.of(parameters.textureFix, (self, u, v) -> super.texture(u, v)); - overlayFix = Applicate.of(parameters.overlayFix, (self, u, v) -> super.overlay(u, v)); - lightFix = Applicate.of(parameters.lightFix, (self, u, v) -> super.light(u, v)); + colorFix = Applicate.of(parameters.colorFix, ColorFix.NULL, super::color, (newR, newG, newB, newA) -> { + buffer[0] = newR / 255F; + buffer[1] = newG / 255F; + buffer[2] = newB / 255F; + buffer[3] = newA / 255F; + }); + textureFix = Applicate.of(parameters.textureFix, FUvFix.NULL, super::texture, (u, v) -> { + buffer[4] = u; + buffer[5] = v; + }); + overlayFix = Applicate.of(parameters.overlayFix, IUvFix.NULL, super::overlay, (u, v) -> { + buffer[6] = u; + buffer[7] = v; + }); } @Override public VertexConsumer color(int r, int g, int b, int a) { - colorFix.getFix().apply(this, r, g, b, a); + colorFix.getFix().apply(colorFix.setter, r, g, b, a); colorFix.nested = false; return this; } @Override public VertexConsumer texture(float u, float v) { - textureFix.getFix().apply(this, u, v); + textureFix.getFix().apply(textureFix.setter, u, v); textureFix.nested = false; return this; } @Override public VertexConsumer overlay(int u, int v) { - overlayFix.getFix().apply(this, u, v); + overlayFix.getFix().apply(overlayFix.setter, u, v); overlayFix.nested = false; return this; } @Override - public VertexConsumer light(int u, int v) { - lightFix.getFix().apply(this, u, v); - lightFix.nested = false; - return this; + public void vertex(float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) { + colorFix.getFix().apply(colorFix.collector, (int)(red * 255), (int)(green * 255F), (int)(blue * 255), (int)(alpha * 255)); + colorFix.nested = false; + textureFix.getFix().apply(textureFix.collector, u, v); + textureFix.nested = false; + overlayFix.getFix().apply(overlayFix.collector, overlay & 0xFFFF, overlay >> 16 & 0xFFFF); + overlayFix.nested = false; + super.vertex(x, y, z, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], (int)buffer[6] | (int)buffer[7] << 16, light, normalX, normalY, normalZ); } public static class Parameters { private @Nullable ColorFix colorFix; private @Nullable FUvFix textureFix; private @Nullable IUvFix overlayFix; - private @Nullable IUvFix lightFix; public Parameters color(ColorFix fix) { colorFix = fix; @@ -68,25 +82,24 @@ public class PassThroughVertexConsumer extends VertexConsumers.Union implements return this; } - public Parameters light(IUvFix fix) { - lightFix = fix; - return this; - } - public VertexConsumer build(VertexConsumer parent) { return new PassThroughVertexConsumer(parent, this); } } - private static class Applicate { + private static class Applicate, V> { public final T fix; public final T fallback; + public final V setter; + public final V collector; public boolean nested; - public Applicate(T fix, T fallback) { + public Applicate(T fix, T fallback, V setter, V collector) { this.fix = fix; this.fallback = fallback; + this.setter = setter; + this.collector = collector; } public T getFix() { @@ -97,21 +110,48 @@ public class PassThroughVertexConsumer extends VertexConsumers.Union implements } } - static Applicate of(@Nullable T fix, T fallback) { - return new Applicate<>(fix == null ? fallback : fix, fallback); + static , V> Applicate of(@Nullable T fix, T fallback, V setter, V collector) { + return new Applicate<>(fix == null ? fallback : fix, fallback, setter, collector); + } + + interface Applicatable { + } } - public interface PosFix { + public interface PosFix extends Applicate.Applicatable { void apply(VertexConsumer consumer, float x, float y, float z); + + public interface VertexConsumer { + void vertex(float x, float y, float z); + } } - public interface ColorFix { + public interface ColorFix extends Applicate.Applicatable { + ColorFix NULL = (self, r, g, b, a) -> self.color(r, g, b, a); void apply(VertexConsumer consumer, int r, int g, int b, int a); + + public interface VertexConsumer { + void color(int r, int g, int b, int a); + + default void color(float r, float g, float b, float a) { + color((int)(r * 255), (int)(g * 255), (int)(b * 255), (int)(a * 255)); + } + } } - public interface FUvFix { + public interface FUvFix extends Applicate.Applicatable { + FUvFix NULL = (self, u, v) -> self.uv(u, v); void apply(VertexConsumer consumer, float u, float v); + + public interface VertexConsumer { + void uv(float u, float v); + } } - public interface IUvFix { + public interface IUvFix extends Applicate.Applicatable { + IUvFix NULL = (self, u, v) -> self.uv(u, v); void apply(VertexConsumer consumer, int u, int v); + + public interface VertexConsumer { + void uv(int u, int v); + } } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java index 152dab5b..c53f2143 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java @@ -74,10 +74,14 @@ public class WorldRenderDelegate { float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light) { if (!recurseMinion && pony instanceof Creature creature && creature.isMinion()) { - recurseMinion = true; - dispatcher.render(creature.asEntity(), x, y, z, yaw, tickDelta, matrices, layer -> MINION_OVERLAY.build(vertices.getBuffer(layer)), light); - recurseMinion = false; - + try { + recurseMinion = true; + dispatcher.render(creature.asEntity(), x, y, z, yaw, tickDelta, matrices, layer -> { + return MINION_OVERLAY.build(vertices.getBuffer(layer)); + }, light); + } finally { + recurseMinion = false; + } return true; } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index f0533b18..77f87250 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -56,6 +56,13 @@ public class Creature extends Living implements WeaklyOwned.Mutabl private boolean discordedChanged = true; + private final Predicate targetPredicate = TargetSelecter.notOwnerOrFriend(this, this).and(e -> { + return Equine.of(e) + .filter(eq -> eq instanceof Creature) + .filter(eq -> ((Creature)eq).hasCommonOwner(this)) + .isEmpty(); + }); + public Creature(LivingEntity entity) { super(entity, EFFECT); physics = new EntityPhysics<>(entity, GRAVITY); @@ -77,7 +84,7 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } public boolean isMinion() { - return owner.getId().isPresent(); + return getMasterReference().isSet(); } public boolean isDiscorded() { @@ -92,13 +99,15 @@ public class Creature extends Living implements WeaklyOwned.Mutabl @Override @NotNull public LivingEntity getMaster() { - NbtCompound data = entity.getDataTracker().get(MASTER); - owner.fromNBT(data); - return owner.getOrEmpty(asWorld()).orElse(entity); + return getMasterReference().getOrEmpty(asWorld()).orElse(entity); } @Override public EntityReference getMasterReference() { + if (entity.getDataTracker().containsKey(MASTER)) { + NbtCompound data = entity.getDataTracker().get(MASTER); + owner.fromNBT(data); + } return owner; } @@ -127,7 +136,7 @@ public class Creature extends Living implements WeaklyOwned.Mutabl goals.add(3, eatMuffinGoal); } - if (owner.isPresent(asWorld())) { + if (getMasterReference().isSet()) { initMinionAi(targets); } @@ -143,18 +152,13 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } } - private void initMinionAi(GoalSelector targets) { - Predicate filter = TargetSelecter.notOwnerOrFriend(this, this).and(e -> { - return Equine.of(e) - .filter(eq -> eq instanceof Creature) - .filter(eq -> ((Creature)eq).hasCommonOwner(this)) - .isEmpty(); - }); + + private void initMinionAi(GoalSelector targets) { clearGoals(targets); - targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, PlayerEntity.class, true, filter)); - targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, HostileEntity.class, true, filter)); - targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, SlimeEntity.class, true, filter)); + targets.add(2, new ActiveEnemyGoal<>(PlayerEntity.class)); + targets.add(2, new ActiveEnemyGoal<>(HostileEntity.class)); + targets.add(2, new ActiveEnemyGoal<>(SlimeEntity.class)); } private void initDiscordedAi() { @@ -189,6 +193,9 @@ public class Creature extends Living implements WeaklyOwned.Mutabl discordedChanged = false; initDiscordedAi(); } + + + return false; } @@ -273,7 +280,7 @@ public class Creature extends Living implements WeaklyOwned.Mutabl getSpellSlot().get(true).ifPresent(effect -> { compound.put("effect", Spell.writeNbt(effect)); }); - compound.put("master", owner.toNBT()); + compound.put("master", getMasterReference().toNBT()); physics.toNBT(compound); compound.putBoolean("discorded", isDiscorded()); } @@ -286,11 +293,26 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } if (compound.contains("master", NbtElement.COMPOUND_TYPE)) { owner.fromNBT(compound.getCompound("master")); - if (owner.isPresent(asWorld())) { + if (entity.getDataTracker().containsKey(MASTER)) { + entity.getDataTracker().set(MASTER, owner.toNBT()); + } + if (owner.isSet()) { targets.ifPresent(this::initMinionAi); } } physics.fromNBT(compound); setDiscorded(compound.getBoolean("discorded")); } + + private class ActiveEnemyGoal extends ActiveTargetGoal { + public ActiveEnemyGoal(Class targetClass) { + super((MobEntity)entity, targetClass, true, Creature.this.targetPredicate); + } + + @Override + public boolean shouldContinue() { + LivingEntity target = this.mob.getTarget(); + return target != null && targetPredicate.test(mob, target) && super.shouldContinue(); + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java index b350209c..a9a09c64 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java @@ -80,6 +80,10 @@ public class EntityReference implements NbtSerialisable { return pos; } + public boolean isSet() { + return getId().isPresent(); + } + public boolean referenceEquals(Entity entity) { return entity != null && entity.getUuid().equals(uuid.orElse(null)); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/FloatingArtefactEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/FloatingArtefactEntity.java index 6f60e7e0..771b5aba 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/FloatingArtefactEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/FloatingArtefactEntity.java @@ -3,8 +3,6 @@ package com.minelittlepony.unicopia.entity; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.entity.damage.UDamageSources; import com.minelittlepony.unicopia.item.UItems; -import com.minelittlepony.unicopia.network.Channel; -import com.minelittlepony.unicopia.network.MsgSpawnProjectile; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -14,8 +12,6 @@ import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.listener.ClientPlayPacketListener; import net.minecraft.util.ActionResult; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d;