Fixed faithful entities not remembering their owner after a save and reload. #136

This commit is contained in:
Sollace 2023-08-05 17:39:56 +01:00
parent 47a2046188
commit 238ca4bff7
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
6 changed files with 133 additions and 63 deletions

View file

@ -29,11 +29,8 @@ public class TargetSelecter {
public Stream<Entity> getEntities(Caster<?> source, double radius, BiPredicate<Caster<?>, Entity> filter) { public Stream<Entity> getEntities(Caster<?> source, double radius, BiPredicate<Caster<?>, Entity> filter) {
targets.values().removeIf(Target::tick); targets.values().removeIf(Target::tick);
Predicate<Entity> ownerCheck = isOwnerOrFriend(spell, source);
return source.findAllEntitiesInRange(radius) 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(entity -> !(entity instanceof SpellbookEntity))
.filter(e -> filter.test(source, e)) .filter(e -> filter.test(source, e))
.map(i -> { .map(i -> {
@ -47,19 +44,26 @@ public class TargetSelecter {
} }
public static <T extends Entity> Predicate<T> notOwnerOrFriend(Affine spell, Caster<?> source) { public static <T extends Entity> Predicate<T> notOwnerOrFriend(Affine spell, Caster<?> source) {
return TargetSelecter.<T>isOwnerOrFriend(spell, source).negate(); return target -> notOwnerOrFriend(spell, source, target);
} }
public static <T extends Entity> Predicate<T> isOwnerOrFriend(Affine spell, Caster<?> source) { public static <T extends Entity> Predicate<T> isOwnerOrFriend(Affine spell, Caster<?> source) {
return target -> isOwnerOrFriend(spell, source, target);
}
public static <T extends Entity> boolean notOwnerOrFriend(Affine spell, Caster<?> source, Entity target) {
return !isOwnerOrFriend(spell, source, target);
}
public static <T extends Entity> boolean isOwnerOrFriend(Affine spell, Caster<?> source, Entity target) {
Entity owner = source.getMaster(); Entity owner = source.getMaster();
if (!(spell.isFriendlyTogether(source) && EquinePredicates.PLAYER_UNICORN.test(owner))) { 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, target)
return FriendshipBraceletItem.isComrade(source, entity) || (owner != null && (Pony.equal(entity, owner) || owner.isConnectedThroughVehicle(entity))); || (owner != null && (Pony.equal(target, owner) || owner.isConnectedThroughVehicle(target)));
};
} }
static final class Target { static final class Target {

View file

@ -6,52 +6,66 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumers; import net.minecraft.client.render.VertexConsumers;
public class PassThroughVertexConsumer extends VertexConsumers.Union implements VertexConsumer { public class PassThroughVertexConsumer extends VertexConsumers.Union implements VertexConsumer {
private final Applicate<ColorFix> colorFix; private final float[] buffer = new float[8];
private final Applicate<FUvFix> textureFix;
private final Applicate<IUvFix> overlayFix; private final Applicate<ColorFix, ColorFix.VertexConsumer> colorFix;
private final Applicate<IUvFix> lightFix; private final Applicate<FUvFix, FUvFix.VertexConsumer> textureFix;
private final Applicate<IUvFix, IUvFix.VertexConsumer> overlayFix;
private PassThroughVertexConsumer(VertexConsumer parent, Parameters parameters) { private PassThroughVertexConsumer(VertexConsumer parent, Parameters parameters) {
super(new VertexConsumer[] {parent}); super(new VertexConsumer[] {parent});
colorFix = Applicate.of(parameters.colorFix, (self, r, g, b, a) -> super.color(r, g, b, a)); colorFix = Applicate.of(parameters.colorFix, ColorFix.NULL, super::color, (newR, newG, newB, newA) -> {
textureFix = Applicate.of(parameters.textureFix, (self, u, v) -> super.texture(u, v)); buffer[0] = newR / 255F;
overlayFix = Applicate.of(parameters.overlayFix, (self, u, v) -> super.overlay(u, v)); buffer[1] = newG / 255F;
lightFix = Applicate.of(parameters.lightFix, (self, u, v) -> super.light(u, v)); 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 @Override
public VertexConsumer color(int r, int g, int b, int a) { 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; colorFix.nested = false;
return this; return this;
} }
@Override @Override
public VertexConsumer texture(float u, float v) { public VertexConsumer texture(float u, float v) {
textureFix.getFix().apply(this, u, v); textureFix.getFix().apply(textureFix.setter, u, v);
textureFix.nested = false; textureFix.nested = false;
return this; return this;
} }
@Override @Override
public VertexConsumer overlay(int u, int v) { public VertexConsumer overlay(int u, int v) {
overlayFix.getFix().apply(this, u, v); overlayFix.getFix().apply(overlayFix.setter, u, v);
overlayFix.nested = false; overlayFix.nested = false;
return this; return this;
} }
@Override @Override
public VertexConsumer light(int u, int v) { 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) {
lightFix.getFix().apply(this, u, v); colorFix.getFix().apply(colorFix.collector, (int)(red * 255), (int)(green * 255F), (int)(blue * 255), (int)(alpha * 255));
lightFix.nested = false; colorFix.nested = false;
return this; 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 { public static class Parameters {
private @Nullable ColorFix colorFix; private @Nullable ColorFix colorFix;
private @Nullable FUvFix textureFix; private @Nullable FUvFix textureFix;
private @Nullable IUvFix overlayFix; private @Nullable IUvFix overlayFix;
private @Nullable IUvFix lightFix;
public Parameters color(ColorFix fix) { public Parameters color(ColorFix fix) {
colorFix = fix; colorFix = fix;
@ -68,25 +82,24 @@ public class PassThroughVertexConsumer extends VertexConsumers.Union implements
return this; return this;
} }
public Parameters light(IUvFix fix) {
lightFix = fix;
return this;
}
public VertexConsumer build(VertexConsumer parent) { public VertexConsumer build(VertexConsumer parent) {
return new PassThroughVertexConsumer(parent, this); return new PassThroughVertexConsumer(parent, this);
} }
} }
private static class Applicate<T> { private static class Applicate<T extends Applicate.Applicatable<V>, V> {
public final T fix; public final T fix;
public final T fallback; public final T fallback;
public final V setter;
public final V collector;
public boolean nested; public boolean nested;
public Applicate(T fix, T fallback) { public Applicate(T fix, T fallback, V setter, V collector) {
this.fix = fix; this.fix = fix;
this.fallback = fallback; this.fallback = fallback;
this.setter = setter;
this.collector = collector;
} }
public T getFix() { public T getFix() {
@ -97,21 +110,48 @@ public class PassThroughVertexConsumer extends VertexConsumers.Union implements
} }
} }
static <T> Applicate<T> of(@Nullable T fix, T fallback) { static <T extends Applicate.Applicatable<V>, V> Applicate<T, V> of(@Nullable T fix, T fallback, V setter, V collector) {
return new Applicate<>(fix == null ? fallback : fix, fallback); return new Applicate<>(fix == null ? fallback : fix, fallback, setter, collector);
}
interface Applicatable<T> {
} }
} }
public interface PosFix { public interface PosFix extends Applicate.Applicatable<PosFix.VertexConsumer> {
void apply(VertexConsumer consumer, float x, float y, float z); 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.VertexConsumer> {
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); 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.VertexConsumer> {
FUvFix NULL = (self, u, v) -> self.uv(u, v);
void apply(VertexConsumer consumer, float u, float 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.VertexConsumer> {
IUvFix NULL = (self, u, v) -> self.uv(u, v);
void apply(VertexConsumer consumer, int u, int v); void apply(VertexConsumer consumer, int u, int v);
public interface VertexConsumer {
void uv(int u, int v);
}
} }
} }

View file

@ -74,10 +74,14 @@ public class WorldRenderDelegate {
float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light) { float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light) {
if (!recurseMinion && pony instanceof Creature creature && creature.isMinion()) { if (!recurseMinion && pony instanceof Creature creature && creature.isMinion()) {
recurseMinion = true; try {
dispatcher.render(creature.asEntity(), x, y, z, yaw, tickDelta, matrices, layer -> MINION_OVERLAY.build(vertices.getBuffer(layer)), light); recurseMinion = true;
recurseMinion = false; dispatcher.render(creature.asEntity(), x, y, z, yaw, tickDelta, matrices, layer -> {
return MINION_OVERLAY.build(vertices.getBuffer(layer));
}, light);
} finally {
recurseMinion = false;
}
return true; return true;
} }

View file

@ -56,6 +56,13 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
private boolean discordedChanged = true; private boolean discordedChanged = true;
private final Predicate<LivingEntity> targetPredicate = TargetSelecter.<LivingEntity>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) { public Creature(LivingEntity entity) {
super(entity, EFFECT); super(entity, EFFECT);
physics = new EntityPhysics<>(entity, GRAVITY); physics = new EntityPhysics<>(entity, GRAVITY);
@ -77,7 +84,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
} }
public boolean isMinion() { public boolean isMinion() {
return owner.getId().isPresent(); return getMasterReference().isSet();
} }
public boolean isDiscorded() { public boolean isDiscorded() {
@ -92,13 +99,15 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
@Override @Override
@NotNull @NotNull
public LivingEntity getMaster() { public LivingEntity getMaster() {
NbtCompound data = entity.getDataTracker().get(MASTER); return getMasterReference().getOrEmpty(asWorld()).orElse(entity);
owner.fromNBT(data);
return owner.getOrEmpty(asWorld()).orElse(entity);
} }
@Override @Override
public EntityReference<LivingEntity> getMasterReference() { public EntityReference<LivingEntity> getMasterReference() {
if (entity.getDataTracker().containsKey(MASTER)) {
NbtCompound data = entity.getDataTracker().get(MASTER);
owner.fromNBT(data);
}
return owner; return owner;
} }
@ -127,7 +136,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
goals.add(3, eatMuffinGoal); goals.add(3, eatMuffinGoal);
} }
if (owner.isPresent(asWorld())) { if (getMasterReference().isSet()) {
initMinionAi(targets); initMinionAi(targets);
} }
@ -143,18 +152,13 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
} }
} }
private void initMinionAi(GoalSelector targets) {
Predicate<LivingEntity> filter = TargetSelecter.<LivingEntity>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); clearGoals(targets);
targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, PlayerEntity.class, true, filter)); targets.add(2, new ActiveEnemyGoal<>(PlayerEntity.class));
targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, HostileEntity.class, true, filter)); targets.add(2, new ActiveEnemyGoal<>(HostileEntity.class));
targets.add(2, new ActiveTargetGoal<>((MobEntity)entity, SlimeEntity.class, true, filter)); targets.add(2, new ActiveEnemyGoal<>(SlimeEntity.class));
} }
private void initDiscordedAi() { private void initDiscordedAi() {
@ -189,6 +193,9 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
discordedChanged = false; discordedChanged = false;
initDiscordedAi(); initDiscordedAi();
} }
return false; return false;
} }
@ -273,7 +280,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
getSpellSlot().get(true).ifPresent(effect -> { getSpellSlot().get(true).ifPresent(effect -> {
compound.put("effect", Spell.writeNbt(effect)); compound.put("effect", Spell.writeNbt(effect));
}); });
compound.put("master", owner.toNBT()); compound.put("master", getMasterReference().toNBT());
physics.toNBT(compound); physics.toNBT(compound);
compound.putBoolean("discorded", isDiscorded()); compound.putBoolean("discorded", isDiscorded());
} }
@ -286,11 +293,26 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
} }
if (compound.contains("master", NbtElement.COMPOUND_TYPE)) { if (compound.contains("master", NbtElement.COMPOUND_TYPE)) {
owner.fromNBT(compound.getCompound("master")); 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); targets.ifPresent(this::initMinionAi);
} }
} }
physics.fromNBT(compound); physics.fromNBT(compound);
setDiscorded(compound.getBoolean("discorded")); setDiscorded(compound.getBoolean("discorded"));
} }
private class ActiveEnemyGoal<T extends LivingEntity> extends ActiveTargetGoal<T> {
public ActiveEnemyGoal(Class<T> 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();
}
}
} }

View file

@ -80,6 +80,10 @@ public class EntityReference<T extends Entity> implements NbtSerialisable {
return pos; return pos;
} }
public boolean isSet() {
return getId().isPresent();
}
public boolean referenceEquals(Entity entity) { public boolean referenceEquals(Entity entity) {
return entity != null && entity.getUuid().equals(uuid.orElse(null)); return entity != null && entity.getUuid().equals(uuid.orElse(null));
} }

View file

@ -3,8 +3,6 @@ package com.minelittlepony.unicopia.entity;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.entity.damage.UDamageSources; import com.minelittlepony.unicopia.entity.damage.UDamageSources;
import com.minelittlepony.unicopia.item.UItems; 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.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
@ -14,8 +12,6 @@ import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; 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.ActionResult;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;