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) {
targets.values().removeIf(Target::tick);
Predicate<Entity> 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 <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) {
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();
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 {

View file

@ -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> colorFix;
private final Applicate<FUvFix> textureFix;
private final Applicate<IUvFix> overlayFix;
private final Applicate<IUvFix> lightFix;
private final float[] buffer = new float[8];
private final Applicate<ColorFix, ColorFix.VertexConsumer> colorFix;
private final Applicate<FUvFix, FUvFix.VertexConsumer> textureFix;
private final Applicate<IUvFix, IUvFix.VertexConsumer> 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<T> {
private static class Applicate<T extends Applicate.Applicatable<V>, 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 <T> Applicate<T> of(@Nullable T fix, T fallback) {
return new Applicate<>(fix == null ? fallback : fix, 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, 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);
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);
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);
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);
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) {
if (!recurseMinion && pony instanceof Creature creature && creature.isMinion()) {
try {
recurseMinion = true;
dispatcher.render(creature.asEntity(), x, y, z, yaw, tickDelta, matrices, layer -> MINION_OVERLAY.build(vertices.getBuffer(layer)), light);
dispatcher.render(creature.asEntity(), x, y, z, yaw, tickDelta, matrices, layer -> {
return MINION_OVERLAY.build(vertices.getBuffer(layer));
}, light);
} finally {
recurseMinion = false;
}
return true;
}

View file

@ -56,6 +56,13 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
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) {
super(entity, EFFECT);
physics = new EntityPhysics<>(entity, GRAVITY);
@ -77,7 +84,7 @@ public class Creature extends Living<LivingEntity> 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<LivingEntity> 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<LivingEntity> 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<LivingEntity> 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<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);
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<LivingEntity> implements WeaklyOwned.Mutabl
discordedChanged = false;
initDiscordedAi();
}
return false;
}
@ -273,7 +280,7 @@ public class Creature extends Living<LivingEntity> 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<LivingEntity> 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<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;
}
public boolean isSet() {
return getId().isPresent();
}
public boolean referenceEquals(Entity entity) {
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.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;