Cast spells are now their own entity (should fix problems with spells dissapearing/not appearing at the correct location in muliplayer)

This commit is contained in:
Sollace 2021-03-04 22:35:49 +02:00
parent f511e2b346
commit 3211b232cf
16 changed files with 296 additions and 100 deletions

View file

@ -0,0 +1,10 @@
package com.minelittlepony.unicopia;
import net.minecraft.entity.Entity;
public interface EntitySupplier {
/**
* Gets the owner that holds this object.
*/
Entity getEntity();
}

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia; package com.minelittlepony.unicopia;
import com.minelittlepony.unicopia.entity.CastSpellEntity;
import com.minelittlepony.unicopia.entity.FloatingArtefactEntity; import com.minelittlepony.unicopia.entity.FloatingArtefactEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
@ -20,6 +21,9 @@ public interface UEntities {
EntityType<FloatingArtefactEntity> FLOATING_ARTEFACT = register("floating_artefact", FabricEntityTypeBuilder.create(SpawnGroup.MISC, FloatingArtefactEntity::new) EntityType<FloatingArtefactEntity> FLOATING_ARTEFACT = register("floating_artefact", FabricEntityTypeBuilder.create(SpawnGroup.MISC, FloatingArtefactEntity::new)
.trackRangeBlocks(200) .trackRangeBlocks(200)
.dimensions(EntityDimensions.fixed(1, 1))); .dimensions(EntityDimensions.fixed(1, 1)));
EntityType<CastSpellEntity> CAST_SPELL = register("cast_spell", FabricEntityTypeBuilder.create(SpawnGroup.MISC, CastSpellEntity::new)
.trackRangeBlocks(200)
.dimensions(EntityDimensions.fixed(1, 1)));
static <T extends Entity> EntityType<T> register(String name, FabricEntityTypeBuilder<T> builder) { static <T extends Entity> EntityType<T> register(String name, FabricEntityTypeBuilder<T> builder) {
EntityType<T> type = builder.build(); EntityType<T> type = builder.build();

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability.magic; package com.minelittlepony.unicopia.ability.magic;
import java.util.UUID;
import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
@ -15,6 +17,11 @@ public interface Spell extends NbtSerialisable, Affine {
*/ */
SpellType<?> getType(); SpellType<?> getType();
/**
* The unique id of this particular spell instance.
*/
UUID getUuid();
/** /**
* Sets this effect as dead. * Sets this effect as dead.
*/ */

View file

@ -2,25 +2,19 @@ package com.minelittlepony.unicopia.ability.magic.spell;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.UEntities;
import com.minelittlepony.unicopia.ability.magic.Attached; import com.minelittlepony.unicopia.ability.magic.Attached;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.entity.CastSpellEntity;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect; import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleHandle; import com.minelittlepony.unicopia.particle.ParticleHandle;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public abstract class AbstractPlacedSpell extends AbstractSpell implements Attached { public abstract class AbstractPlacedSpell extends AbstractSpell implements Attached {
@Nullable
protected Vec3d origin;
@Nullable
protected BlockPos placement;
@Nullable @Nullable
private Identifier dimension; private Identifier dimension;
@ -39,39 +33,45 @@ public abstract class AbstractPlacedSpell extends AbstractSpell implements Attac
@Override @Override
public boolean onBodyTick(Caster<?> source) { public boolean onBodyTick(Caster<?> source) {
if (origin == null) { if (!source.isClient()) {
origin = source.getOriginVector();
placement = source.getOrigin(); if (dimension == null) {
dimension = source.getWorld().getRegistryKey().getValue(); dimension = source.getWorld().getRegistryKey().getValue();
setDirty(true);
if (!source.isClient()) {
CastSpellEntity entity = UEntities.CAST_SPELL.create(source.getWorld());
Vec3d pos = source.getOriginVector();
entity.updatePositionAndAngles(pos.x, pos.y, pos.z, 0, 0);
entity.setSpell(this);
entity.setMaster(source.getMaster());
entity.world.spawnEntity(entity);
}
}
if (!source.getWorld().getRegistryKey().getValue().equals(dimension)) {
return false;
}
} }
if (!source.getWorld().getRegistryKey().getValue().equals(dimension)) { return true;
return false;
}
if (source.isClient()) {
particlEffect.ifAbsent(source, spawner -> {
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), origin, Vec3d.ZERO);
}).ifPresent(p -> {
p.attach(source);
p.setAttribute(1, getType().getColor());
});
}
return onGroundTick(source);
} }
protected abstract boolean onGroundTick(Caster<?> source); public boolean onGroundTick(Caster<?> source) {
particlEffect.ifAbsent(source, spawner -> {
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
}).ifPresent(p -> {
p.attach(source);
p.setAttribute(1, getType().getColor());
});
return true;
}
@Override @Override
public void toNBT(CompoundTag compound) { public void toNBT(CompoundTag compound) {
super.toNBT(compound); super.toNBT(compound);
if (placement != null) {
compound.put("placement", NbtHelper.fromBlockPos(placement));
}
if (origin != null) {
compound.put("origin", NbtSerialisable.writeVector(origin));
}
if (dimension != null) { if (dimension != null) {
compound.putString("dimension", dimension.toString()); compound.putString("dimension", dimension.toString());
} }
@ -80,12 +80,7 @@ public abstract class AbstractPlacedSpell extends AbstractSpell implements Attac
@Override @Override
public void fromNBT(CompoundTag compound) { public void fromNBT(CompoundTag compound) {
super.fromNBT(compound); super.fromNBT(compound);
if (compound.contains("placement")) {
placement = NbtHelper.toBlockPos(compound.getCompound("placement"));
}
if (compound.contains("origin")) {
origin = NbtSerialisable.readVector(compound.getList("origin", 6));
}
if (compound.contains("dimension")) { if (compound.contains("dimension")) {
dimension = new Identifier(compound.getString("dimension")); dimension = new Identifier(compound.getString("dimension"));
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.UUID;
import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.Spell;
@ -12,8 +14,16 @@ public abstract class AbstractSpell implements Spell {
private final SpellType<?> type; private final SpellType<?> type;
private UUID uuid;
protected AbstractSpell(SpellType<?> type) { protected AbstractSpell(SpellType<?> type) {
this.type = type; this.type = type;
uuid = UUID.randomUUID();
}
@Override
public final UUID getUuid() {
return uuid;
} }
@Override @Override
@ -49,11 +59,15 @@ public abstract class AbstractSpell implements Spell {
@Override @Override
public void toNBT(CompoundTag compound) { public void toNBT(CompoundTag compound) {
compound.putBoolean("dead", isDead); compound.putBoolean("dead", isDead);
compound.putUuid("uuid", uuid);
} }
@Override @Override
public void fromNBT(CompoundTag compound) { public void fromNBT(CompoundTag compound) {
setDirty(false); setDirty(false);
if (compound.contains("uuid")) {
uuid = compound.getUuid("uuid");
}
isDead = compound.getBoolean("dead"); isDead = compound.getBoolean("dead");
} }
} }

View file

@ -31,11 +31,12 @@ public class NecromancySpell extends AbstractPlacedSpell {
@Override @Override
public boolean onGroundTick(Caster<?> source) { public boolean onGroundTick(Caster<?> source) {
super.onGroundTick(source);
int radius = (source.getLevel().get() + 1) * 4; int radius = (source.getLevel().get() + 1) * 4;
if (source.isClient()) { if (source.isClient()) {
source.spawnParticles(origin, new Sphere(false, radius), 5, pos -> { source.spawnParticles(new Sphere(false, radius), 5, pos -> {
if (!source.getWorld().isAir(new BlockPos(pos).down())) { if (!source.getWorld().isAir(new BlockPos(pos).down())) {
source.addParticle(ParticleTypes.FLAME, pos, Vec3d.ZERO); source.addParticle(ParticleTypes.FLAME, pos, Vec3d.ZERO);
} }
@ -47,7 +48,7 @@ public class NecromancySpell extends AbstractPlacedSpell {
return true; return true;
} }
float additional = source.getWorld().getLocalDifficulty(placement).getLocalDifficulty(); float additional = source.getWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty();
Shape affectRegion = new Sphere(false, radius); Shape affectRegion = new Sphere(false, radius);
@ -60,7 +61,7 @@ public class NecromancySpell extends AbstractPlacedSpell {
} }
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
Vec3d pos = affectRegion.computePoint(source.getWorld().random).add(origin); Vec3d pos = affectRegion.computePoint(source.getWorld().random).add(source.getOriginVector());
BlockPos loc = new BlockPos(pos); BlockPos loc = new BlockPos(pos);

View file

@ -32,16 +32,17 @@ public class SiphoningSpell extends AbstractPlacedSpell {
@Override @Override
public boolean onGroundTick(Caster<?> source) { public boolean onGroundTick(Caster<?> source) {
super.onGroundTick(source);
if (source.isClient()) { if (source.isClient()) {
int radius = 4 + source.getLevel().get(); int radius = 4 + source.getLevel().get();
int direction = isFriendlyTogether(source) ? 1 : -1; int direction = isFriendlyTogether(source) ? 1 : -1;
source.spawnParticles(origin, new Sphere(true, radius, 1, 0, 1), 1, pos -> { source.spawnParticles(new Sphere(true, radius, 1, 0, 1), 1, pos -> {
if (!source.getWorld().isAir(new BlockPos(pos).down())) { if (!source.getWorld().isAir(new BlockPos(pos).down())) {
double dist = pos.distanceTo(origin); double dist = pos.distanceTo(source.getOriginVector());
Vec3d velocity = pos.subtract(origin).normalize().multiply(direction * dist); Vec3d velocity = pos.subtract(source.getOriginVector()).normalize().multiply(direction * dist);
source.addParticle(direction == 1 ? ParticleTypes.HEART : ParticleTypes.ANGRY_VILLAGER, pos, velocity); source.addParticle(direction == 1 ? ParticleTypes.HEART : ParticleTypes.ANGRY_VILLAGER, pos, velocity);
} }
@ -62,7 +63,7 @@ public class SiphoningSpell extends AbstractPlacedSpell {
} }
private Stream<LivingEntity> getTargets(Caster<?> source) { private Stream<LivingEntity> getTargets(Caster<?> source) {
return VecHelper.findInRange(null, source.getWorld(), origin, 4 + source.getLevel().get(), e -> e instanceof LivingEntity) return VecHelper.findInRange(null, source.getWorld(), source.getOriginVector(), 4 + source.getLevel().get(), e -> e instanceof LivingEntity)
.stream() .stream()
.map(e -> (LivingEntity)e); .map(e -> (LivingEntity)e);
} }

View file

@ -15,6 +15,7 @@ import com.minelittlepony.unicopia.client.particle.SphereParticle;
import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer; import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer;
import com.minelittlepony.unicopia.client.render.AmuletFeatureRenderer; import com.minelittlepony.unicopia.client.render.AmuletFeatureRenderer;
import com.minelittlepony.unicopia.client.render.BraceletFeatureRenderer; import com.minelittlepony.unicopia.client.render.BraceletFeatureRenderer;
import com.minelittlepony.unicopia.client.render.CastSpellEntityRenderer;
import com.minelittlepony.unicopia.client.render.FloatingArtefactEntityRenderer; import com.minelittlepony.unicopia.client.render.FloatingArtefactEntityRenderer;
import com.minelittlepony.unicopia.client.render.WingsFeatureRenderer; import com.minelittlepony.unicopia.client.render.WingsFeatureRenderer;
import com.minelittlepony.unicopia.item.ChameleonItem; import com.minelittlepony.unicopia.item.ChameleonItem;
@ -61,6 +62,7 @@ public interface URenderers {
EntityRendererRegistry.INSTANCE.register(UEntities.THROWN_ITEM, (manager, context) -> new FlyingItemEntityRenderer<>(manager, context.getItemRenderer())); EntityRendererRegistry.INSTANCE.register(UEntities.THROWN_ITEM, (manager, context) -> new FlyingItemEntityRenderer<>(manager, context.getItemRenderer()));
EntityRendererRegistry.INSTANCE.register(UEntities.FLOATING_ARTEFACT, FloatingArtefactEntityRenderer::new); EntityRendererRegistry.INSTANCE.register(UEntities.FLOATING_ARTEFACT, FloatingArtefactEntityRenderer::new);
EntityRendererRegistry.INSTANCE.register(UEntities.CAST_SPELL, CastSpellEntityRenderer::new);
ColorProviderRegistry.ITEM.register((stack, i) -> i > 0 ? -1 : ((DyeableItem)stack.getItem()).getColor(stack), UItems.FRIENDSHIP_BRACELET); ColorProviderRegistry.ITEM.register((stack, i) -> i > 0 ? -1 : ((DyeableItem)stack.getItem()).getColor(stack), UItems.FRIENDSHIP_BRACELET);
BuiltinItemRendererRegistry.INSTANCE.register(UItems.FILLED_JAR, (stack, mode, matrices, vertexConsumers, light, overlay) -> { BuiltinItemRendererRegistry.INSTANCE.register(UItems.FILLED_JAR, (stack, mode, matrices, vertexConsumers, light, overlay) -> {

View file

@ -0,0 +1,21 @@
package com.minelittlepony.unicopia.client.render;
import com.minelittlepony.unicopia.entity.CastSpellEntity;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.util.Identifier;
public class CastSpellEntityRenderer extends EntityRenderer<CastSpellEntity> {
public CastSpellEntityRenderer(EntityRenderDispatcher dispatcher, EntityRendererRegistry.Context context) {
super(dispatcher);
}
@Override
public Identifier getTexture(CastSpellEntity entity) {
return SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE;
}
}

View file

@ -0,0 +1,154 @@
package com.minelittlepony.unicopia.entity;
import java.util.Optional;
import java.util.UUID;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Levelled;
import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractPlacedSpell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellPredicate;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.EffectSync;
import com.minelittlepony.unicopia.network.MsgSpawnProjectile;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Packet;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.World;
public class CastSpellEntity extends Entity implements Caster<LivingEntity> {
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Optional<UUID>> SPELL = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
private static final SpellPredicate<AbstractPlacedSpell> SPELL_TYPE = s -> s instanceof AbstractPlacedSpell;
private static final LevelStore LEVELS = Levelled.fixed(0);
private final EntityPhysics<CastSpellEntity> physics = new EntityPhysics<>(this, GRAVITY);
private UUID ownerUuid;
private int ownerEntityId;
public CastSpellEntity(EntityType<?> type, World world) {
super(type, world);
}
@Override
protected void initDataTracker() {
getDataTracker().startTracking(SPELL, Optional.empty());
}
@Override
public void tick() {
super.tick();
if (removed) {
return;
}
LivingEntity master = getMaster();
if (master == null || master.removed) {
remove();
return;
}
if (!Caster.of(master).filter(c -> {
UUID spellId = dataTracker.get(SPELL).orElse(null);
if (!c.getSpellSlot().get(SPELL_TYPE, true).filter(s -> s.getUuid().equals(spellId) && s.onGroundTick(this)).isPresent()) {
c.setSpell(null);
return false;
}
return true;
}).isPresent()) {
remove();
}
}
@Override
public void setMaster(LivingEntity owner) {
if (owner != null) {
ownerUuid = owner.getUuid();
ownerEntityId = owner.getEntityId();
}
}
@Override
public void setSpell(Spell spell) {
getDataTracker().set(SPELL, Optional.ofNullable(spell).map(Spell::getUuid));
}
@Override
public Entity getEntity() {
return this;
}
@Override
public LivingEntity getMaster() {
if (ownerUuid != null && world instanceof ServerWorld) {
return (LivingEntity)((ServerWorld)world).getEntity(ownerUuid);
}
if (ownerEntityId != 0) {
return (LivingEntity)world.getEntityById(ownerEntityId);
}
return null;
}
@Override
public LevelStore getLevel() {
return Caster.of(getMaster()).map(Caster::getLevel).orElse(LEVELS);
}
@Override
public Affinity getAffinity() {
return getSpellSlot().get(true).map(Spell::getAffinity).orElse(Affinity.NEUTRAL);
}
@Override
public Physics getPhysics() {
return physics;
}
@Override
public EffectSync getSpellSlot() {
return Caster.of(getMaster()).map(Caster::getSpellSlot).orElse(null);
}
@Override
protected void writeCustomDataToTag(CompoundTag tag) {
if (ownerUuid != null) {
tag.putUuid("Owner", ownerUuid);
}
tag.putInt("OwnerId", ownerEntityId);
}
@Override
protected void readCustomDataFromTag(CompoundTag tag) {
if (tag.containsUuid("Owner")) {
ownerUuid = tag.getUuid("Owner");
}
ownerEntityId = tag.getInt("OwnerId");
}
@Override
public Packet<?> createSpawnPacket() {
return Channel.SERVER_SPAWN_PROJECTILE.toPacket(new MsgSpawnProjectile(this));
}
}

View file

@ -30,10 +30,11 @@ public class Creature extends Living<LivingEntity> {
public static void boostrap() {} public static void boostrap() {}
private final EntityPhysics<Creature> physics = new EntityPhysics<>(this, GRAVITY); private final EntityPhysics<LivingEntity> physics;
public Creature(LivingEntity entity) { public Creature(LivingEntity entity) {
super(entity, EFFECT); super(entity, EFFECT);
physics = new EntityPhysics<>(entity, GRAVITY);
} }
public void initAi(GoalSelector goals, GoalSelector targets) { public void initAi(GoalSelector goals, GoalSelector targets) {

View file

@ -1,6 +1,5 @@
package com.minelittlepony.unicopia.entity; package com.minelittlepony.unicopia.entity;
import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.entity.player.PlayerAttributes; import com.minelittlepony.unicopia.entity.player.PlayerAttributes;
import com.minelittlepony.unicopia.util.Copieable; import com.minelittlepony.unicopia.util.Copieable;
@ -22,31 +21,29 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class EntityPhysics<T extends Owned<? extends Entity>> implements Physics, Copieable<EntityPhysics<T>>, Tickable { public class EntityPhysics<T extends Entity> implements Physics, Copieable<EntityPhysics<T>>, Tickable {
private final TrackedData<Float> gravity; private final TrackedData<Float> gravity;
protected final T pony; protected final T entity;
private float lastGravity = 1; private float lastGravity = 1;
public EntityPhysics(T pony, TrackedData<Float> gravity) { public EntityPhysics(T entity, TrackedData<Float> gravity) {
this(pony, gravity, true); this(entity, gravity, true);
} }
public EntityPhysics(T pony, TrackedData<Float> gravity, boolean register) { public EntityPhysics(T entity, TrackedData<Float> gravity, boolean register) {
this.pony = pony; this.entity = entity;
this.gravity = gravity; this.gravity = gravity;
if (register) { if (register) {
this.pony.getMaster().getDataTracker().startTracking(gravity, 1F); this.entity.getDataTracker().startTracking(gravity, 1F);
} }
} }
@Override @Override
public void tick() { public void tick() {
Entity entity = pony.getMaster();
if (isGravityNegative()) { if (isGravityNegative()) {
if (entity.getY() > entity.world.getHeight() + 64) { if (entity.getY() > entity.world.getHeight() + 64) {
entity.damage(DamageSource.OUT_OF_WORLD, 4.0F); entity.damage(DamageSource.OUT_OF_WORLD, 4.0F);
@ -64,8 +61,6 @@ public class EntityPhysics<T extends Owned<? extends Entity>> implements Physics
} }
protected void onGravitychanged() { protected void onGravitychanged() {
Entity entity = pony.getMaster();
entity.calculateDimensions(); entity.calculateDimensions();
if (!entity.world.isClient && entity instanceof MobEntity) { if (!entity.world.isClient && entity instanceof MobEntity) {
@ -81,7 +76,7 @@ public class EntityPhysics<T extends Owned<? extends Entity>> implements Physics
@Override @Override
public Vec3d getMotionAngle() { public Vec3d getMotionAngle() {
return new Vec3d(pony.getMaster().getPitch(1), pony.getMaster().getYaw(1), 0); return new Vec3d(entity.getPitch(1), entity.getYaw(1), 0);
} }
@Override @Override
@ -92,8 +87,6 @@ public class EntityPhysics<T extends Owned<? extends Entity>> implements Physics
@Override @Override
public BlockPos getHeadPosition() { public BlockPos getHeadPosition() {
Entity entity = pony.getMaster();
entity.setOnGround(false); entity.setOnGround(false);
BlockPos pos = new BlockPos( BlockPos pos = new BlockPos(
@ -118,7 +111,6 @@ public class EntityPhysics<T extends Owned<? extends Entity>> implements Physics
@Override @Override
public void spawnSprintingParticles() { public void spawnSprintingParticles() {
Entity entity = pony.getMaster();
BlockState state = entity.world.getBlockState(getHeadPosition()); BlockState state = entity.world.getBlockState(getHeadPosition());
if (state.getRenderType() != BlockRenderType.INVISIBLE) { if (state.getRenderType() != BlockRenderType.INVISIBLE) {
Vec3d vel = entity.getVelocity(); Vec3d vel = entity.getVelocity();
@ -132,31 +124,29 @@ public class EntityPhysics<T extends Owned<? extends Entity>> implements Physics
@Override @Override
public void setBaseGravityModifier(float constant) { public void setBaseGravityModifier(float constant) {
pony.getMaster().getDataTracker().set(gravity, constant); entity.getDataTracker().set(gravity, constant);
} }
@Override @Override
public float getBaseGravityModifier() { public float getBaseGravityModifier() {
return pony.getMaster().getDataTracker().get(gravity); return entity.getDataTracker().get(gravity);
} }
@Override @Override
public float getGravityModifier() { public float getGravityModifier() {
Entity master = pony.getMaster();
if (entity instanceof LivingEntity) {
if (master instanceof LivingEntity) { if (((LivingEntity)entity).getAttributes() == null) {
if (((LivingEntity)master).getAttributes() == null) {
// may be null due to order of execution in the constructor. // may be null due to order of execution in the constructor.
// Will have the default (1) here in any case, so it's safe to ignore the attribute at this point. // Will have the default (1) here in any case, so it's safe to ignore the attribute at this point.
return getBaseGravityModifier(); return getBaseGravityModifier();
} }
if (((LivingEntity)master).isSleeping()) { if (((LivingEntity)entity).isSleeping()) {
return 1; return 1;
} }
return getBaseGravityModifier() * (float)((LivingEntity)master).getAttributeValue(PlayerAttributes.ENTITY_GRAVTY_MODIFIER); return getBaseGravityModifier() * (float)((LivingEntity)entity).getAttributeValue(PlayerAttributes.ENTITY_GRAVTY_MODIFIER);
} }
return getBaseGravityModifier(); return getBaseGravityModifier();

View file

@ -30,12 +30,13 @@ public class ItemImpl implements Equine<ItemEntity>, Owned<ItemEntity> {
private final ItemEntity owner; private final ItemEntity owner;
private final ItemPhysics physics = new ItemPhysics(this); private final ItemPhysics physics;
private Race serverRace; private Race serverRace;
public ItemImpl(ItemEntity owner) { public ItemImpl(ItemEntity owner) {
this.owner = owner; this.owner = owner;
this.physics = new ItemPhysics(owner);
owner.getDataTracker().startTracking(ITEM_GRAVITY, 1F); owner.getDataTracker().startTracking(ITEM_GRAVITY, 1F);
owner.getDataTracker().startTracking(ITEM_RACE, Race.HUMAN.ordinal()); owner.getDataTracker().startTracking(ITEM_RACE, Race.HUMAN.ordinal());
} }

View file

@ -3,43 +3,41 @@ package com.minelittlepony.unicopia.entity;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity; import net.minecraft.entity.ItemEntity;
class ItemPhysics extends EntityPhysics<ItemImpl> { class ItemPhysics extends EntityPhysics<ItemEntity> {
public ItemPhysics(ItemImpl itemImpl) { public ItemPhysics(ItemEntity entity) {
super(itemImpl, ItemImpl.ITEM_GRAVITY, false); super(entity, ItemImpl.ITEM_GRAVITY, false);
} }
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
ItemEntity owner = pony.getMaster(); if (isGravityNegative() && !entity.getStack().isEmpty()) {
entity.setNoGravity(true);
if (isGravityNegative() && !owner.getStack().isEmpty()) { entity.addVelocity(
owner.setNoGravity(true);
owner.addVelocity(
0, 0,
0.04 0.04
+ calcGravity(-0.04D), // apply our own + calcGravity(-0.04D), // apply our own
0 0
); );
if (!owner.isOnGround() if (!entity.isOnGround()
|| Entity.squaredHorizontalLength(owner.getVelocity()) > 9.999999747378752E-6D) { || Entity.squaredHorizontalLength(entity.getVelocity()) > 9.999999747378752E-6D) {
float above = 0.98f; float above = 0.98f;
if (owner.verticalCollision) { if (entity.verticalCollision) {
above *= owner.world.getBlockState(owner.getBlockPos().up()).getBlock().getSlipperiness(); above *= entity.world.getBlockState(entity.getBlockPos().up()).getBlock().getSlipperiness();
//above /= 9; //above /= 9;
} }
owner.setVelocity(owner.getVelocity().multiply(above, 1, above)); entity.setVelocity(entity.getVelocity().multiply(above, 1, above));
} }
} }
} }
@Override @Override
protected void onGravitychanged() { protected void onGravitychanged() {
if (!pony.getMaster().world.isClient) { if (!entity.world.isClient) {
float gravity = this.getBaseGravityModifier(); float gravity = this.getBaseGravityModifier();
setBaseGravityModifier(gravity == 0 ? 1 : gravity * 2); setBaseGravityModifier(gravity == 0 ? 1 : gravity * 2);
setBaseGravityModifier(gravity); setBaseGravityModifier(gravity);

View file

@ -38,7 +38,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Motion, NbtSerialisable { public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickable, Motion, NbtSerialisable {
private int ticksInAir; private int ticksInAir;
@ -55,8 +55,11 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
private final PlayerDimensions dimensions; private final PlayerDimensions dimensions;
private final Pony pony;
public PlayerPhysics(Pony pony) { public PlayerPhysics(Pony pony) {
super(pony, Creature.GRAVITY); super(pony.getMaster(), Creature.GRAVITY);
this.pony = pony;
dimensions = new PlayerDimensions(pony, this); dimensions = new PlayerDimensions(pony, this);
} }
@ -67,12 +70,12 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
@Override @Override
public boolean isFlying() { public boolean isFlying() {
return isFlyingSurvival && !pony.getMaster().isFallFlying() && !pony.getMaster().hasVehicle(); return isFlyingSurvival && !entity.isFallFlying() && !entity.hasVehicle();
} }
@Override @Override
public boolean isGliding() { public boolean isGliding() {
return isFlying() && (pony.getMaster().isSneaking() || ((Jumper)pony.getMaster()).isJumping()) && !pony.sneakingChanged(); return isFlying() && (entity.isSneaking() || ((Jumper)entity).isJumping()) && !pony.sneakingChanged();
} }
@Override @Override
@ -84,8 +87,6 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
public float getWingAngle() { public float getWingAngle() {
float spreadAmount = -0.5F; float spreadAmount = -0.5F;
PlayerEntity entity = pony.getMaster();
if (isFlying()) { if (isFlying()) {
//spreadAmount += Math.sin(pony.getEntity().age / 4F) * 8; //spreadAmount += Math.sin(pony.getEntity().age / 4F) * 8;
spreadAmount += isGliding() ? 3 : thrustScale * 60; spreadAmount += isGliding() ? 3 : thrustScale * 60;
@ -109,7 +110,6 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
if (wallHitCooldown > 0) { if (wallHitCooldown > 0) {
wallHitCooldown--; wallHitCooldown--;
} }
PlayerEntity entity = pony.getMaster();
final MutableVector velocity = new MutableVector(entity.getVelocity()); final MutableVector velocity = new MutableVector(entity.getVelocity());
@ -121,7 +121,7 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
entity.setPose(EntityPose.STANDING); entity.setPose(EntityPose.STANDING);
} }
boolean creative = entity.abilities.creativeMode || pony.getMaster().isSpectator(); boolean creative = entity.abilities.creativeMode || entity.isSpectator();
FlightType type = getFlightType(); FlightType type = getFlightType();
@ -443,7 +443,7 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
private FlightType getFlightType() { private FlightType getFlightType() {
if (UItems.PEGASUS_AMULET.isApplicable(pony.getMaster())) { if (UItems.PEGASUS_AMULET.isApplicable(entity)) {
return FlightType.ARTIFICIAL; return FlightType.ARTIFICIAL;
} }
@ -454,8 +454,6 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
} }
public void updateFlightStat(boolean flying) { public void updateFlightStat(boolean flying) {
PlayerEntity entity = pony.getMaster();
FlightType type = getFlightType(); FlightType type = getFlightType();
entity.abilities.allowFlying = type.canFlyCreative(entity); entity.abilities.allowFlying = type.canFlyCreative(entity);
@ -484,6 +482,6 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
isFlyingEither = compound.getBoolean("isFlyingEither"); isFlyingEither = compound.getBoolean("isFlyingEither");
ticksInAir = compound.getInt("ticksInAir"); ticksInAir = compound.getInt("ticksInAir");
pony.getMaster().calculateDimensions(); entity.calculateDimensions();
} }
} }

View file

@ -6,7 +6,6 @@ import java.util.function.Consumer;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.entity.Equine;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
@ -82,7 +81,7 @@ public class ParticleHandle {
caster = caster.filter(c -> { caster = caster.filter(c -> {
Entity e = c.getEntity(); Entity e = c.getEntity();
return Equine.of(e) == c return Caster.of(e).orElse(null) == c
&& c.getSpellSlot().get(false) && c.getSpellSlot().get(false)
.filter(s -> s.getType() == effect) .filter(s -> s.getType() == effect)
.isPresent() .isPresent()