Physics rewrite for better gravity manipulation

This commit is contained in:
Sollace 2020-05-10 17:18:45 +02:00
parent 298eddb9c2
commit 5b7f298147
41 changed files with 812 additions and 741 deletions

View file

@ -8,7 +8,6 @@ import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.Updatable;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.MsgPlayerAbility; import com.minelittlepony.unicopia.network.MsgPlayerAbility;
import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.Channel;
@ -16,8 +15,9 @@ import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Tickable;
public class AbilityDispatcher implements Updatable, NbtSerialisable { public class AbilityDispatcher implements Tickable, NbtSerialisable {
private final Pony player; private final Pony player;
@ -88,7 +88,7 @@ public class AbilityDispatcher implements Updatable, NbtSerialisable {
} }
@Override @Override
public void onUpdate() { public void tick() {
getActiveAbility().ifPresent(this::activate); getActiveAbility().ifPresent(this::activate);
} }

View file

@ -28,8 +28,8 @@ public class CarryAbility implements Ability<Hit> {
} }
@Override @Override
public boolean canUse(Race playerSpecies) { public boolean canUse(Race race) {
return playerSpecies.canFly(); return race.canFly();
} }
@Override @Override

View file

@ -74,7 +74,7 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
return disc; return disc;
}).setDisguise(looked); }).setDisguise(looked);
iplayer.sendCapabilities(true); iplayer.setDirty();
} }
@Override @Override

View file

@ -42,8 +42,8 @@ public class ChangelingFeedAbility implements Ability<Hit> {
} }
@Override @Override
public boolean canUse(Race playerSpecies) { public boolean canUse(Race race) {
return playerSpecies == Race.CHANGELING; return race == Race.CHANGELING;
} }
@Nullable @Nullable

View file

@ -33,8 +33,8 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
} }
@Override @Override
public boolean canUse(Race playerSpecies) { public boolean canUse(Race race) {
return playerSpecies == Race.EARTH; return race == Race.EARTH;
} }
@Override @Override

View file

@ -64,8 +64,8 @@ public class EarthPonyStompAbility implements Ability<Multi> {
} }
@Override @Override
public boolean canUse(Race playerSpecies) { public boolean canUse(Race race) {
return playerSpecies.canUseEarth(); return race.canUseEarth();
} }
@Nullable @Nullable

View file

@ -25,8 +25,8 @@ public class PegasusCloudInteractionAbility implements Ability<Numeric> {
} }
@Override @Override
public boolean canUse(Race playerSpecies) { public boolean canUse(Race race) {
return playerSpecies.canInteractWithClouds(); return race.canInteractWithClouds();
} }
@Override @Override

View file

@ -23,8 +23,8 @@ public class UnicornCastingAbility implements Ability<Hit> {
} }
@Override @Override
public boolean canUse(Race playerSpecies) { public boolean canUse(Race race) {
return playerSpecies.canCast(); return race.canCast();
} }
@Override @Override

View file

@ -0,0 +1,67 @@
package com.minelittlepony.unicopia.client.render;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
public class WorldRenderDelegate {
public static final WorldRenderDelegate INSTANCE = new WorldRenderDelegate();
public void beforeEntityRender(Pony pony, MatrixStack matrices, double x, double y, double z) {
if (pony.getPhysics().isGravityNegative()) {
matrices.push();
Entity entity = pony.getOwner();
matrices.translate(x, y, z);
matrices.translate(0, entity.getHeight(), 0);
matrices.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(180));
matrices.translate(-x, -y, -z);
flipAngles(entity);
}
}
public void afterEntityRender(Pony pony, MatrixStack matrices) {
if (pony.getPhysics().isGravityNegative()) {
matrices.pop();
flipAngles(pony.getOwner());
}
}
private void flipAngles(Entity entity) {
if (MinecraftClient.getInstance().options.perspective > 0) {
entity.prevYaw *= -1;
entity.yaw *= -1;
if (entity instanceof LivingEntity) {
LivingEntity living = (LivingEntity)entity;
living.bodyYaw = -living.bodyYaw;
living.prevBodyYaw = -living.prevBodyYaw;
living.headYaw = -living.headYaw;
living.prevHeadYaw = -living.prevHeadYaw;
}
}
entity.prevPitch *= -1;
entity.pitch *= -1;
}
public void applyWorldTransform(MatrixStack matrices, float tickDelta) {
PlayerEntity player = MinecraftClient.getInstance().player;
if (player != null && MinecraftClient.getInstance().cameraEntity == player) {
float roll = Pony.of(player).getCamera().calculateRoll();
matrices.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(roll));
}
}
}

View file

@ -39,7 +39,7 @@ class GravityCommand {
Pony iplayer = Pony.of(player); Pony iplayer = Pony.of(player);
float gravity = iplayer.getGravity().getGravitationConstant(); float gravity = iplayer.getPhysics().getGravityModifier();
if (source.getPlayer() != player) { if (source.getPlayer() != player) {
translationKey += ".other"; translationKey += ".other";
@ -54,8 +54,8 @@ class GravityCommand {
Pony iplayer = Pony.of(player); Pony iplayer = Pony.of(player);
iplayer.getGravity().setGraviationConstant(gravity); iplayer.getPhysics().setGravityModifier(gravity);
iplayer.sendCapabilities(true); iplayer.setDirty();
if (isSelf) { if (isSelf) {
player.sendMessage(new TranslatableText(translationKey, gravity)); player.sendMessage(new TranslatableText(translationKey, gravity));

View file

@ -49,7 +49,7 @@ class SpeciesCommand {
if (race.isPermitted(player)) { if (race.isPermitted(player)) {
Pony pony = Pony.of(player); Pony pony = Pony.of(player);
pony.setSpecies(race); pony.setSpecies(race);
pony.sendCapabilities(false); pony.setDirty();
Text formattedName = new TranslatableText(race.name().toLowerCase()); Text formattedName = new TranslatableText(race.name().toLowerCase());

View file

@ -1,8 +1,8 @@
package com.minelittlepony.unicopia.ducks; package com.minelittlepony.unicopia.ducks;
import com.minelittlepony.unicopia.entity.ItemEntityCapabilities; import com.minelittlepony.unicopia.entity.ItemImpl;
public interface IItemEntity extends PonyContainer<ItemEntityCapabilities> { public interface IItemEntity extends PonyContainer<ItemImpl> {
int getAge(); int getAge();

View file

@ -10,9 +10,9 @@ import com.minelittlepony.unicopia.magic.Caster;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
public interface PonyContainer<T extends Ponylike> { public interface PonyContainer<T extends Ponylike<?>> {
Ponylike create(); Ponylike<?> create();
T get(); T get();
@ -28,7 +28,7 @@ public interface PonyContainer<T extends Ponylike> {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <E extends Entity, T extends Ponylike> Optional<PonyContainer<T>> of(Entity entity) { static <E extends Entity, T extends Ponylike<?>> Optional<PonyContainer<T>> of(Entity entity) {
if (entity instanceof PonyContainer) { if (entity instanceof PonyContainer) {
return Optional.of(((PonyContainer<T>)entity)); return Optional.of(((PonyContainer<T>)entity));
} }

View file

@ -15,7 +15,7 @@ import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
public class LivingEntityCapabilities implements RaceContainer<LivingEntity>, Caster<LivingEntity> { public class Creature implements Ponylike<LivingEntity>, Caster<LivingEntity> {
private static final TrackedData<CompoundTag> EFFECT = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.TAG_COMPOUND); private static final TrackedData<CompoundTag> EFFECT = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.TAG_COMPOUND);
@ -23,9 +23,11 @@ public class LivingEntityCapabilities implements RaceContainer<LivingEntity>, Ca
private final EffectSync effectDelegate = new EffectSync(this, EFFECT); private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
private final Physics physics = new EntityPhysics<>(this);
private final LivingEntity entity; private final LivingEntity entity;
public LivingEntityCapabilities(LivingEntity entity) { public Creature(LivingEntity entity) {
this.entity = entity; this.entity = entity;
entity.getDataTracker().startTracking(EFFECT, new CompoundTag()); entity.getDataTracker().startTracking(EFFECT, new CompoundTag());
@ -36,6 +38,11 @@ public class LivingEntityCapabilities implements RaceContainer<LivingEntity>, Ca
return Race.HUMAN; return Race.HUMAN;
} }
@Override
public Physics getPhysics() {
return physics;
}
@Override @Override
public void setSpecies(Race race) { public void setSpecies(Race race) {
} }
@ -56,7 +63,7 @@ public class LivingEntityCapabilities implements RaceContainer<LivingEntity>, Ca
} }
@Override @Override
public void onUpdate() { public void tick() {
if (hasEffect()) { if (hasEffect()) {
AttachedMagicEffect effect = getEffect(AttachedMagicEffect.class, true); AttachedMagicEffect effect = getEffect(AttachedMagicEffect.class, true);
@ -72,11 +79,6 @@ public class LivingEntityCapabilities implements RaceContainer<LivingEntity>, Ca
} }
} }
@Override
public void onDimensionalTravel(int destinationDimension) {
}
@Override @Override
public void setOwner(LivingEntity owner) { public void setOwner(LivingEntity owner) {
@ -111,6 +113,7 @@ public class LivingEntityCapabilities implements RaceContainer<LivingEntity>, Ca
if (effect != null) { if (effect != null) {
compound.put("effect", SpellRegistry.instance().serializeEffectToNBT(effect)); compound.put("effect", SpellRegistry.instance().serializeEffectToNBT(effect));
} }
physics.toNBT(compound);
} }
@Override @Override
@ -118,5 +121,6 @@ public class LivingEntityCapabilities implements RaceContainer<LivingEntity>, Ca
if (compound.contains("effect")) { if (compound.contains("effect")) {
setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompound("effect"))); setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompound("effect")));
} }
physics.fromNBT(compound);
} }
} }

View file

@ -40,7 +40,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules; import net.minecraft.world.GameRules;
import net.minecraft.world.World; import net.minecraft.world.World;
public class CuccoonEntity extends LivingEntity implements IMagicals, InAnimate { public class CuccoonEntity extends LivingEntity implements IMagicals, InAnimate, Trap {
private static final TrackedData<Integer> STRUGGLE_COUNT = DataTracker.registerData(CuccoonEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData<Integer> STRUGGLE_COUNT = DataTracker.registerData(CuccoonEntity.class, TrackedDataHandlerRegistry.INTEGER);
@ -206,6 +206,7 @@ public class CuccoonEntity extends LivingEntity implements IMagicals, InAnimate
return true; return true;
} }
@Override
public boolean attemptDismount(Entity captive) { public boolean attemptDismount(Entity captive) {
if (captive.isSneaking() != captiveLastSneakState) { if (captive.isSneaking() != captiveLastSneakState) {
setStruggleCount(getStruggleCount() + 1); setStruggleCount(getStruggleCount() + 1);

View file

@ -0,0 +1,101 @@
package com.minelittlepony.unicopia.entity;
import net.minecraft.block.Block;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.FenceGateBlock;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.particle.BlockStateParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.tag.BlockTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class EntityPhysics<T extends Ponylike<?> & Owned<? extends Entity>> implements Physics {
private float gravity = 1;
protected final T pony;
public EntityPhysics(T pony) {
this.pony = pony;
}
@Override
public boolean isFlying() {
return false;
}
@Override
public double calcGravity(double worldConstant) {
return worldConstant * gravity;
}
@Override
public BlockPos getHeadPosition() {
pony.getOwner().onGround = false;
int i = MathHelper.floor(pony.getOwner().getX());
int j = MathHelper.floor(pony.getOwner().getY() + pony.getOwner().getHeight() + 0.20000000298023224D);
int k = MathHelper.floor(pony.getOwner().getZ());
BlockPos blockPos = new BlockPos(i, j, k);
if (pony.getOwner().world.getBlockState(blockPos).isAir()) {
BlockPos blockPos2 = blockPos.down();
BlockState blockState = pony.getOwner().world.getBlockState(blockPos2);
Block block = blockState.getBlock();
if (block.matches(BlockTags.FENCES) || block.matches(BlockTags.WALLS) || block instanceof FenceGateBlock) {
pony.getOwner().onGround = true;
return blockPos2;
}
} else {
pony.getOwner().onGround = true;
}
return blockPos;
}
@Override
public void spawnSprintingParticles() {
Entity entity = pony.getOwner();
BlockState state = entity.world.getBlockState(getHeadPosition());
if (state.getRenderType() != BlockRenderType.INVISIBLE) {
Vec3d vel = entity.getVelocity();
entity.world.addParticle(new BlockStateParticleEffect(ParticleTypes.BLOCK, state),
entity.getX() + (entity.world.random.nextFloat() - 0.5D) * entity.getWidth(),
entity.getY() + entity.getHeight() - 0.1D,
entity.getZ() + (entity.world.random.nextFloat() - 0.5D) * entity.getWidth(),
vel.x * -4, -1.5D, vel.z * -4);
}
}
@Override
public void setGravityModifier(float constant) {
gravity = constant;
}
@Override
public float getGravityModifier() {
return gravity;
}
@Override
public void toNBT(CompoundTag compound) {
if (gravity != 0) {
compound.putFloat("gravity", gravity);
}
}
@Override
public void fromNBT(CompoundTag compound) {
if (compound.contains("gravity")) {
gravity = compound.getFloat("gravity");
} else {
gravity = 0;
}
}
}

View file

@ -11,19 +11,21 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
public class ItemEntityCapabilities implements RaceContainer<ItemEntity>, Owned<ItemEntity> { public class ItemImpl implements Ponylike<ItemEntity>, Owned<ItemEntity> {
private static final TrackedData<Integer> ITEM_RACE = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.INTEGER); private static final TrackedData<Integer> ITEM_RACE = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.INTEGER);
private final ItemEntity owner; private final ItemEntity owner;
private Race serverRace; private Race serverRace;
public ItemEntityCapabilities(ItemEntity owner) { private final Physics physics = new EntityPhysics<>(this);
public ItemImpl(ItemEntity owner) {
this.owner = owner; this.owner = owner;
owner.getDataTracker().startTracking(ITEM_RACE, Race.HUMAN.ordinal()); owner.getDataTracker().startTracking(ITEM_RACE, Race.HUMAN.ordinal());
} }
@Override @Override
public void onUpdate() { public void tick() {
} }
@Override @Override
@ -47,6 +49,11 @@ public class ItemEntityCapabilities implements RaceContainer<ItemEntity>, Owned<
return false; return false;
} }
@Override
public Physics getPhysics() {
return physics;
}
@Override @Override
public Race getSpecies() { public Race getSpecies() {
return Race.fromId(getOwner().getDataTracker().get(ITEM_RACE)); return Race.fromId(getOwner().getDataTracker().get(ITEM_RACE));
@ -60,12 +67,14 @@ public class ItemEntityCapabilities implements RaceContainer<ItemEntity>, Owned<
@Override @Override
public void toNBT(CompoundTag compound) { public void toNBT(CompoundTag compound) {
compound.putString("owner_species", getSpecies().name()); compound.putString("owner_species", getSpecies().name());
physics.toNBT(compound);
} }
@Override @Override
public void fromNBT(CompoundTag compound) { public void fromNBT(CompoundTag compound) {
setSpecies(Race.fromName(compound.getString("owner_species"))); setSpecies(Race.fromName(compound.getString("owner_species")));
physics.fromNBT(compound);
} }
@Override @Override
@ -73,11 +82,6 @@ public class ItemEntityCapabilities implements RaceContainer<ItemEntity>, Owned<
} }
@Override
public void onDimensionalTravel(int destinationDimension) {
}
@Override @Override
public ItemEntity getOwner() { public ItemEntity getOwner() {
return owner; return owner;

View file

@ -0,0 +1,28 @@
package com.minelittlepony.unicopia.entity;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.util.math.BlockPos;
public interface Physics extends NbtSerialisable {
double calcGravity(double worldConstant);
float getGravityModifier();
void setGravityModifier(float constant);
boolean isFlying();
BlockPos getHeadPosition();
void spawnSprintingParticles();
default boolean isGravityNegative() {
return getGravityModifier() < 0;
}
default int getGravitySignum() {
return (int)Math.signum(getGravityModifier());
}
}

View file

@ -8,13 +8,14 @@ import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.ProjectileEntity; import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.util.Tickable;
public interface Ponylike extends NbtSerialisable, Updatable { public interface Ponylike<T extends Entity> extends NbtSerialisable, Tickable {
Race getSpecies(); Race getSpecies();
void setSpecies(Race race); Physics getPhysics();
void onDimensionalTravel(int destinationDimension); void setSpecies(Race race);
/** /**
* Returns true if this player is fully invisible. * Returns true if this player is fully invisible.
@ -54,7 +55,7 @@ public interface Ponylike extends NbtSerialisable, Updatable {
} }
@Nullable @Nullable
static <T extends Ponylike> T of(Entity entity) { static <T extends Ponylike<?>> T of(Entity entity) {
return PonyContainer.<Entity, T>of(entity) return PonyContainer.<Entity, T>of(entity)
.map(PonyContainer::get) .map(PonyContainer::get)
.orElse(null); .orElse(null);

View file

@ -1,12 +0,0 @@
package com.minelittlepony.unicopia.entity;
import net.minecraft.entity.Entity;
/**
* Generic container for an entity that has a race.
*
* @param <T> The type of owner
*/
public interface RaceContainer<T extends Entity> extends Ponylike {
}

View file

@ -1,12 +0,0 @@
package com.minelittlepony.unicopia.entity;
/**
* Interface for objects that receive regular updates.
*/
@FunctionalInterface
public interface Updatable {
/**
* Called to update the internal logic.
*/
void onUpdate();
}

View file

@ -0,0 +1,32 @@
package com.minelittlepony.unicopia.entity.player;
public class ManaContainer implements MagicReserves {
private final Pony pony;
public ManaContainer(Pony pony) {
this.pony = pony;
pony.getOwner().getDataTracker().startTracking(Pony.ENERGY, 0F);
pony.getOwner().getDataTracker().startTracking(Pony.EXERTION, 0F);
}
@Override
public float getExertion() {
return pony.getOwner().getDataTracker().get(Pony.EXERTION);
}
@Override
public void setExertion(float exertion) {
pony.getOwner().getDataTracker().set(Pony.EXERTION, Math.max(0, exertion));
}
@Override
public float getEnergy() {
return pony.getOwner().getDataTracker().get(Pony.ENERGY);
}
@Override
public void setEnergy(float energy) {
pony.getOwner().getDataTracker().set(Pony.ENERGY, Math.max(0, energy));
}
}

View file

@ -1,9 +1,9 @@
package com.minelittlepony.unicopia.entity; package com.minelittlepony.unicopia.entity.player;
/** /**
* Interface for controlling flight. * Interface for controlling flight.
*/ */
public interface FlightControl { public interface Motion {
/** /**
* True is we're currently flying. * True is we're currently flying.
*/ */
@ -14,4 +14,6 @@ public interface FlightControl {
float getFlightDuration(); float getFlightDuration();
boolean isExperienceCritical(); boolean isExperienceCritical();
PlayerDimensions getDimensions();
} }

View file

@ -18,19 +18,19 @@ public class PlayerCamera extends MotionCompositor {
double roll = baseRoll; double roll = baseRoll;
if (player.getFlight().isFlying()) { if (player.getMotion().isFlying()) {
Vec3d vel = player.getOwner().getVelocity(); Vec3d vel = player.getOwner().getVelocity();
roll -= super.calculateRoll(player.getOwner(), vel.x, vel.y, vel.z); roll -= super.calculateRoll(player.getOwner(), vel.x, vel.y, vel.z);
} }
if (player.getGravity().getGravitationConstant() < 0) { if (player.getPhysics().isGravityNegative()) {
roll = -roll; roll = -roll;
roll += 180; roll += 180;
} }
if (player.getEntity().age > 10) { if (player.getEntity().age > 10) {
roll = player.getInterpolator().interpolate("roll", (float)roll, 250); roll = player.getInterpolator().interpolate("roll", (float)roll, 50);
} }
return (float)roll; return (float)roll;
@ -45,7 +45,7 @@ public class PlayerCamera extends MotionCompositor {
} }
public double calculateFieldOfView(double fov) { public double calculateFieldOfView(double fov) {
fov += player.getMagicalReserves().getExertion() / 5; fov += player.getMagicalReserves().getExertion() / 5F;
fov += getEnergyAddition(); fov += getEnergyAddition();
return fov; return fov;

View file

@ -6,7 +6,7 @@ import com.minelittlepony.unicopia.magic.MagicEffect;
import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityPose; import net.minecraft.entity.EntityPose;
public final class PlayerDimensionsDelegate { public final class PlayerDimensions {
private float defaultEyeHeight; private float defaultEyeHeight;
private float defaultBodyHeight; private float defaultBodyHeight;
@ -14,10 +14,13 @@ public final class PlayerDimensionsDelegate {
private float lastTargetEyeHeight; private float lastTargetEyeHeight;
private float lastTargetBodyHeight; private float lastTargetBodyHeight;
private final GravityDelegate gravity; private final PlayerPhysics physics;
public PlayerDimensionsDelegate(GravityDelegate gravity) { private final Pony pony;
this.gravity = gravity;
public PlayerDimensions(Pony pony, PlayerPhysics gravity) {
this.pony = pony;
this.physics = gravity;
} }
public float getActiveEyeHeight(float original) { public float getActiveEyeHeight(float original) {
@ -46,11 +49,11 @@ public final class PlayerDimensionsDelegate {
private float calculateTargetEyeHeightWithGravity(float targetBodyHeight) { private float calculateTargetEyeHeightWithGravity(float targetBodyHeight) {
float height = calculateTargetEyeHeight(); float height = calculateTargetEyeHeight();
if (gravity.getGravitationConstant() < 0 && gravity.player.getOwner().isSneaking()) { if (physics.isGravityNegative() && pony.getOwner().isSneaking()) {
height += 0.2F; height += 0.2F;
} }
if (gravity.getGravitationConstant() < 0) { if (physics.isGravityNegative()) {
height = targetBodyHeight - height; height = targetBodyHeight - height;
} }
@ -58,17 +61,17 @@ public final class PlayerDimensionsDelegate {
} }
private float calculateTargetEyeHeight() { private float calculateTargetEyeHeight() {
if (gravity.player.hasEffect()) { if (pony.hasEffect()) {
MagicEffect effect = gravity.player.getEffect(); MagicEffect effect = pony.getEffect();
if (!effect.isDead() && effect instanceof HeightPredicate) { if (!effect.isDead() && effect instanceof HeightPredicate) {
float val = ((HeightPredicate)effect).getTargetEyeHeight(gravity.player); float val = ((HeightPredicate)effect).getTargetEyeHeight(pony);
if (val > 0) { if (val > 0) {
return val; return val;
} }
} }
} }
if (gravity.isFlying && gravity.isRainboom()) { if (physics.isFlying && physics.isRainboom()) {
return 0.5F; return 0.5F;
} }
@ -76,17 +79,17 @@ public final class PlayerDimensionsDelegate {
} }
private float calculateTargetBodyHeight() { private float calculateTargetBodyHeight() {
if (gravity.player.hasEffect()) { if (pony.hasEffect()) {
MagicEffect effect = gravity.player.getEffect(); MagicEffect effect = pony.getEffect();
if (!effect.isDead() && effect instanceof HeightPredicate) { if (!effect.isDead() && effect instanceof HeightPredicate) {
float val = ((HeightPredicate)effect).getTargetBodyHeight(gravity.player); float val = ((HeightPredicate)effect).getTargetBodyHeight(pony);
if (val > 0) { if (val > 0) {
return val; return val;
} }
} }
} }
if (gravity.isFlying && gravity.isRainboom()) { if (physics.isFlying && physics.isRainboom()) {
return defaultBodyHeight / 2; return defaultBodyHeight / 2;
} }

View file

@ -1,443 +0,0 @@
package com.minelittlepony.unicopia.entity.player;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.enchanting.PageOwner;
import com.minelittlepony.unicopia.entity.FlightControl;
import com.minelittlepony.unicopia.entity.Trap;
import com.minelittlepony.unicopia.magic.Affinity;
import com.minelittlepony.unicopia.magic.AttachedMagicEffect;
import com.minelittlepony.unicopia.magic.HeldMagicEffect;
import com.minelittlepony.unicopia.magic.MagicEffect;
import com.minelittlepony.unicopia.magic.MagicalItem;
import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.EffectSync;
import com.minelittlepony.unicopia.network.MsgPlayerCapabilities;
import com.minelittlepony.unicopia.toxin.Toxicity;
import com.minelittlepony.unicopia.toxin.Toxin;
import com.minelittlepony.util.BasicEasingInterpolator;
import com.minelittlepony.util.IInterpolator;
import com.mojang.datafixers.util.Either;
import net.minecraft.client.network.packet.EntityPassengersSetS2CPacket;
import net.minecraft.entity.Entity;
import net.minecraft.entity.damage.DamageSource;
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.entity.player.PlayerEntity.SleepFailureReason;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Hand;
import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
public class PlayerImpl implements Pony, MagicReserves {
private static final TrackedData<Integer> PLAYER_RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final TrackedData<Float> ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Float> EXERTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<CompoundTag> EFFECT = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.TAG_COMPOUND);
private static final TrackedData<CompoundTag> HELD_EFFECT = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.TAG_COMPOUND);
private final PlayerPageStats pageStates = new PlayerPageStats();
private final AbilityDispatcher powers = new AbilityDispatcher(this);
private final GravityDelegate gravity = new GravityDelegate(this);
private final PlayerAttributes attributes = new PlayerAttributes();
private final PlayerCamera view = new PlayerCamera(this);
private final PlayerInventory inventory = new PlayerInventory(this);
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
private final EffectSync heldEffectDelegate = new EffectSync(this, HELD_EFFECT);
private final IInterpolator interpolator = new BasicEasingInterpolator();
private float nextStepDistance = 1;
private final PlayerEntity entity;
private boolean dirty = false;
private boolean invisible = false;
public PlayerImpl(PlayerEntity player) {
this.entity = player;
player.getDataTracker().startTracking(PLAYER_RACE, Race.EARTH.ordinal());
player.getDataTracker().startTracking(EXERTION, 0F);
player.getDataTracker().startTracking(ENERGY, 0F);
player.getDataTracker().startTracking(EFFECT, new CompoundTag());
player.getDataTracker().startTracking(HELD_EFFECT, new CompoundTag());
player.getAttributes().register(PlayerAttributes.EXTENDED_REACH_DISTANCE);
}
@Override
public Race getSpecies() {
if (getOwner() == null) {
return Race.HUMAN;
}
return Race.fromId(getOwner().getDataTracker().get(PLAYER_RACE));
}
@Override
public void setSpecies(Race race) {
race = race.validate(entity);
entity.getDataTracker().set(PLAYER_RACE, race.ordinal());
gravity.updateFlightStat(entity, entity.abilities.flying);
entity.sendAbilitiesUpdate();
}
@Override
public MagicReserves getMagicalReserves() {
return this;
}
@Override
public float getExertion() {
return getOwner().getDataTracker().get(EXERTION);
}
@Override
public void setExertion(float exertion) {
entity.getDataTracker().set(EXERTION, Math.max(0, exertion));
}
@Override
public float getEnergy() {
return entity.getDataTracker().get(ENERGY);
}
@Override
public void setEnergy(float energy) {
entity.getDataTracker().set(ENERGY, Math.max(0, energy));
}
@Override
public boolean isInvisible() {
return invisible && hasEffect();
}
@Override
public void setInvisible(boolean invisible) {
this.invisible = invisible;
}
@Nullable
public HeldMagicEffect getHeldEffect(ItemStack stack) {
if (!getSpecies().canCast()) {
heldEffectDelegate.set(null);
return null;
}
HeldMagicEffect heldEffect = heldEffectDelegate.get(HeldMagicEffect.class, true);
if (heldEffect == null || !heldEffect.getName().equals(SpellRegistry.getKeyFromStack(stack))) {
heldEffect = SpellRegistry.instance().getHeldFrom(stack);
heldEffectDelegate.set(heldEffect);
}
return heldEffect;
}
@Override
public Affinity getAffinity() {
return Affinity.NEUTRAL;
}
@Override
public void sendCapabilities(boolean full) {
dirty = false;
if (entity instanceof ServerPlayerEntity) {
System.out.println("Sending capabilities for player");
Channel.BROADCAST_CAPABILITIES.send(new MsgPlayerCapabilities(full, this));
}
}
@Override
public void onDimensionalTravel(int destinationDimension) {
if (!getWorld().isClient()) {
dirty = true;
}
}
@Override
public AbilityDispatcher getAbilities() {
return powers;
}
@Override
public PageOwner getPages() {
return pageStates;
}
@Override
public GravityDelegate getGravity() {
return gravity;
}
@Override
public float getExtendedReach() {
return (float)entity.getAttributeInstance(PlayerAttributes.EXTENDED_REACH_DISTANCE).getValue();
}
@Override
public FlightControl getFlight() {
return gravity;
}
@Override
public PlayerCamera getCamera() {
return view;
}
@Override
public IInterpolator getInterpolator() {
return interpolator;
}
@Override
public boolean beforeUpdate() {
if (entity.world.isClient()) {
if (entity.hasVehicle() && entity.isSneaking()) {
Entity ridee = entity.getVehicle();
if (ridee instanceof Trap) {
if (((Trap)ridee).attemptDismount(entity)) {
entity.stopRiding();
} else {
entity.setSneaking(false);
}
} else {
entity.stopRiding();
if (ridee instanceof ServerPlayerEntity) {
((ServerPlayerEntity)ridee).networkHandler.sendPacket(new EntityPassengersSetS2CPacket(ridee));
}
}
}
}
powers.onUpdate();
inventory.onUpdate();
return false;
}
@Override
public void onUpdate() {
gravity.onUpdate();
if (hasEffect()) {
AttachedMagicEffect effect = getEffect(AttachedMagicEffect.class, true);
if (effect != null) {
if (entity.getEntityWorld().isClient()) {
effect.renderOnPerson(this);
}
if (!effect.updateOnPerson(this)) {
setEffect(null);
}
}
}
ItemStack stack = entity.getStackInHand(Hand.MAIN_HAND);
HeldMagicEffect effect = getHeldEffect(stack);
if (effect != null) {
Affinity affinity = stack.getItem() instanceof MagicalItem ? ((MagicalItem)stack.getItem()).getAffinity(stack) : Affinity.NEUTRAL;
effect.updateInHand(this, affinity);
}
addExertion(-1);
addEnergy(-1);
attributes.applyAttributes(entity, getSpecies());
if (dirty) {
sendCapabilities(true);
}
}
@Override
public float onImpact(float distance) {
if (getSpecies().canFly()) {
distance = Math.max(0, distance - 5);
}
return distance;
}
@Override
public void onJump() {
if (gravity.getGravitationConstant() < 0) {
Vec3d velocity = entity.getVelocity();
entity.setVelocity(velocity.x, velocity.y * -1, velocity.z);
}
}
@Override
public boolean onProjectileImpact(ProjectileEntity projectile) {
if (hasEffect()) {
MagicEffect effect = getEffect();
if (!effect.isDead() && effect.handleProjectileImpact(projectile)) {
return true;
}
}
return false;
}
@Override
public boolean subtractEnergyCost(double foodSubtract) {
if (!entity.abilities.creativeMode) {
int food = (int)(entity.getHungerManager().getFoodLevel() - foodSubtract);
if (food < 0) {
entity.getHungerManager().add(-entity.getHungerManager().getFoodLevel(), 0);
entity.damage(DamageSource.MAGIC, -food/2);
} else {
entity.getHungerManager().add((int)-foodSubtract, 0);
}
}
return entity.getHealth() > 0;
}
@Override
public boolean stepOnCloud() {
if (entity.fallDistance > 1 || entity.distanceTraveled > nextStepDistance) {
nextStepDistance = entity.distanceTraveled + 2;
entity.fallDistance = 0;
return true;
}
return false;
}
@Override
public Either<SleepFailureReason, Unit> trySleep(BlockPos pos) {
if (getInventory().matches(UTags.CURSED_ARTEFACTS)) {
if (!isClient()) {
entity.addChatMessage(new TranslatableText("tile.bed.youAreAMonster"), true);
}
return Either.left(SleepFailureReason.OTHER_PROBLEM);
}
if (findAllSpellsInRange(10).anyMatch(c -> c instanceof Pony && ((Pony)c).getInventory().matches(UTags.CURSED_ARTEFACTS))) {
return Either.left(SleepFailureReason.NOT_SAFE);
}
return Either.right(Unit.INSTANCE);
}
@Override
public PlayerInventory getInventory() {
return inventory;
}
@Override
public void onEat(ItemStack stack) {
if (getSpecies() == Race.CHANGELING) {
Toxin.POISON.afflict(getOwner(), Toxicity.SAFE, stack);
}
}
@Override
public void toNBT(CompoundTag compound) {
compound.putString("playerSpecies", getSpecies().name());
compound.put("powers", powers.toNBT());
compound.put("gravity", gravity.toNBT());
MagicEffect effect = getEffect();
if (effect != null) {
compound.put("effect", SpellRegistry.instance().serializeEffectToNBT(effect));
}
pageStates.toNBT(compound);
}
@Override
public void fromNBT(CompoundTag compound) {
setSpecies(Race.fromName(compound.getString("playerSpecies")));
powers.fromNBT(compound.getCompound("powers"));
gravity.fromNBT(compound.getCompound("gravity"));
if (compound.contains("effect")) {
effectDelegate.set(SpellRegistry.instance().createEffectFromNBT(compound.getCompound("effect")));
}
pageStates.fromNBT(compound);
}
@Override
public void copyFrom(Pony oldPlayer) {
setEffect(oldPlayer.getEffect());
setSpecies(oldPlayer.getSpecies());
sendCapabilities(true);
}
@Override
public void setEffect(@Nullable MagicEffect effect) {
effectDelegate.set(effect);
sendCapabilities(true);
}
@Override
public boolean hasEffect() {
return effectDelegate.has();
}
@Nullable
@Override
public <T extends MagicEffect> T getEffect(@Nullable Class<T> type, boolean update) {
return effectDelegate.get(type, update);
}
@Override
public void setOwner(PlayerEntity owner) {
}
@Override
public PlayerEntity getOwner() {
return entity;
}
@Override
public int getCurrentLevel() {
return 0;
}
@Override
public void setCurrentLevel(int level) {
}
}

View file

@ -4,7 +4,6 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.minelittlepony.unicopia.entity.Updatable;
import com.minelittlepony.unicopia.item.MagicGemItem; import com.minelittlepony.unicopia.item.MagicGemItem;
import com.minelittlepony.unicopia.magic.AddictiveMagicalItem; import com.minelittlepony.unicopia.magic.AddictiveMagicalItem;
import com.minelittlepony.unicopia.magic.MagicalItem; import com.minelittlepony.unicopia.magic.MagicalItem;
@ -16,9 +15,10 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.tag.Tag; import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Tickable;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
public class PlayerInventory implements Updatable, NbtSerialisable { public class PlayerInventory implements Tickable, NbtSerialisable {
private final Map<AddictiveMagicalItem, Entry> dependencies = Maps.newHashMap(); private final Map<AddictiveMagicalItem, Entry> dependencies = Maps.newHashMap();
private final Pony player; private final Pony player;
@ -66,7 +66,7 @@ public class PlayerInventory implements Updatable, NbtSerialisable {
} }
@Override @Override
public synchronized void onUpdate() { public synchronized void tick() {
Iterator<Map.Entry<AddictiveMagicalItem, Entry>> iterator = dependencies.entrySet().iterator(); Iterator<Map.Entry<AddictiveMagicalItem, Entry>> iterator = dependencies.entrySet().iterator();
@ -75,7 +75,7 @@ public class PlayerInventory implements Updatable, NbtSerialisable {
Entry item = entry.getValue(); Entry item = entry.getValue();
item.onUpdate(); item.tick();
if (item.needfulness <= 0.001) { if (item.needfulness <= 0.001) {
iterator.remove(); iterator.remove();
@ -132,7 +132,7 @@ public class PlayerInventory implements Updatable, NbtSerialisable {
}); });
} }
class Entry implements Updatable, NbtSerialisable { class Entry implements Tickable, NbtSerialisable {
int ticksAttached = 0; int ticksAttached = 0;
float needfulness = 1; float needfulness = 1;
@ -152,7 +152,7 @@ public class PlayerInventory implements Updatable, NbtSerialisable {
} }
@Override @Override
public void onUpdate() { public void tick() {
if (isWearing(item)) { if (isWearing(item)) {
ticksAttached ++; ticksAttached ++;
needfulness *= 0.9F; needfulness *= 0.9F;

View file

@ -13,6 +13,12 @@ import net.minecraft.util.Identifier;
public class PlayerPageStats implements NbtSerialisable, PageOwner { public class PlayerPageStats implements NbtSerialisable, PageOwner {
private final Map<Identifier, PageState> pageStates = new HashMap<>(); private final Map<Identifier, PageState> pageStates = new HashMap<>();
private final Pony pony;
PlayerPageStats(Pony pony) {
this.pony = pony;
}
@Override @Override
public Map<Identifier, PageState> getPageStates() { public Map<Identifier, PageState> getPageStates() {
return pageStates; return pageStates;
@ -20,7 +26,7 @@ public class PlayerPageStats implements NbtSerialisable, PageOwner {
@Override @Override
public void sendCapabilities(boolean full) { public void sendCapabilities(boolean full) {
pony.sendCapabilities(full);
} }
@Override @Override

View file

@ -5,8 +5,7 @@ import java.util.Random;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.FlightPredicate; import com.minelittlepony.unicopia.ability.FlightPredicate;
import com.minelittlepony.unicopia.entity.FlightControl; import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.Updatable;
import com.minelittlepony.unicopia.magic.MagicEffect; import com.minelittlepony.unicopia.magic.MagicEffect;
import com.minelittlepony.unicopia.particles.MagicParticleEffect; import com.minelittlepony.unicopia.particles.MagicParticleEffect;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
@ -18,13 +17,12 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Tickable;
import net.minecraft.util.math.BlockPos; 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 GravityDelegate implements Updatable, FlightControl, NbtSerialisable, FlightPredicate { public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Motion, NbtSerialisable {
final Pony player;
private static final float MAXIMUM_FLIGHT_EXPERIENCE = 1500; private static final float MAXIMUM_FLIGHT_EXPERIENCE = 1500;
@ -37,73 +35,63 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
private double lastTickPosX = 0; private double lastTickPosX = 0;
private double lastTickPosZ = 0; private double lastTickPosZ = 0;
private float gravity = 0; private final PlayerDimensions dimensions;
private final PlayerDimensionsDelegate dimensions; public PlayerPhysics(Pony pony) {
super(pony);
public GravityDelegate(Pony player) { dimensions = new PlayerDimensions(pony, this);
this.player = player;
this.dimensions = new PlayerDimensionsDelegate(this);
} }
@Override private boolean checkCanFly() {
public boolean checkCanFly(Pony player) { if (pony.getOwner().abilities.creativeMode) {
if (player.getOwner().abilities.creativeMode) {
return true; return true;
} }
if (player.hasEffect()) { if (pony.hasEffect()) {
MagicEffect effect = player.getEffect(); MagicEffect effect = pony.getEffect();
if (!effect.isDead() && effect instanceof FlightPredicate) { if (!effect.isDead() && effect instanceof FlightPredicate) {
return ((FlightPredicate)effect).checkCanFly(player); return ((FlightPredicate)effect).checkCanFly(pony);
} }
} }
return player.getSpecies().canFly(); return pony.getSpecies().canFly();
} }
protected boolean isRainboom() { protected boolean isRainboom() {
return Math.sqrt(getHorizontalMotion(player.getOwner())) > 0.4F; return Math.sqrt(getHorizontalMotion(pony.getOwner())) > 0.4F;
} }
public PlayerDimensionsDelegate getDimensions() { @Override
public PlayerDimensions getDimensions() {
return dimensions; return dimensions;
} }
public void setGraviationConstant(float constant) {
gravity = constant;
}
public float getGravitationConstant() {
return gravity;
}
@Override @Override
public boolean isExperienceCritical() { public boolean isExperienceCritical() {
return isRainbooming || flightExperience > MAXIMUM_FLIGHT_EXPERIENCE * 0.8; return isRainbooming || flightExperience > MAXIMUM_FLIGHT_EXPERIENCE * 0.8;
} }
@Override @Override
public void onUpdate() { public void tick() {
PlayerEntity entity = player.getOwner(); PlayerEntity entity = pony.getOwner();
MutableVector velocity = new MutableVector(entity.getVelocity()); MutableVector velocity = new MutableVector(entity.getVelocity());
if (isExperienceCritical() && player.isClient()) { if (isExperienceCritical() && pony.isClient()) {
Random rnd = player.getWorld().random; Random rnd = pony.getWorld().random;
for (int i = 0; i < 360 + getHorizontalMotion(entity); i += 10) { for (int i = 0; i < 360 + getHorizontalMotion(entity); i += 10) {
Vec3d pos = player.getOriginVector().add( Vec3d pos = pony.getOriginVector().add(
rnd.nextGaussian() * entity.getWidth(), rnd.nextGaussian() * entity.getWidth(),
rnd.nextGaussian() * entity.getHeight()/2, rnd.nextGaussian() * entity.getHeight()/2,
rnd.nextGaussian() * entity.getWidth() rnd.nextGaussian() * entity.getWidth()
); );
player.addParticle(MagicParticleEffect.UNICORN, pos, velocity.toImmutable()); pony.addParticle(MagicParticleEffect.UNICORN, pos, velocity.toImmutable());
} }
} }
entity.abilities.allowFlying = checkCanFly(player); entity.abilities.allowFlying = checkCanFly();
if (!entity.abilities.creativeMode) { if (!entity.abilities.creativeMode) {
entity.abilities.flying |= entity.abilities.allowFlying && isFlying && !entity.onGround && !entity.isTouchingWater(); entity.abilities.flying |= entity.abilities.allowFlying && isFlying && !entity.onGround && !entity.isTouchingWater();
@ -111,26 +99,6 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
isFlying = entity.abilities.flying && !entity.abilities.creativeMode; isFlying = entity.abilities.flying && !entity.abilities.creativeMode;
if (gravity != 0) {
if (!entity.abilities.flying) {
velocity.y += 0.038;
velocity.y -= gravity;
}
if (gravity < 0) {
entity.onGround = !entity.world.isAir(new BlockPos(entity.getX(), entity.getY() + entity.getHeight() + 0.5F, entity.getZ()));
if (entity.onGround) {
entity.abilities.flying = false;
isFlying = false;
}
}
}
if (dimensions.update()) {
player.getOwner().calculateDimensions();
}
if (!entity.abilities.creativeMode && !entity.isFallFlying()) { if (!entity.abilities.creativeMode && !entity.isFallFlying()) {
if (isFlying && !entity.hasVehicle()) { if (isFlying && !entity.hasVehicle()) {
@ -140,7 +108,7 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
entity.fallDistance = 0; entity.fallDistance = 0;
if (player.getSpecies() != Race.CHANGELING && entity.world.random.nextInt(100) == 0) { if (pony.getSpecies() != Race.CHANGELING && entity.world.random.nextInt(100) == 0) {
float exhaustion = (0.3F * ticksNextLevel) / 70; float exhaustion = (0.3F * ticksNextLevel) / 70;
if (entity.isSprinting()) { if (entity.isSprinting()) {
exhaustion *= 3.11F; exhaustion *= 3.11F;
@ -163,8 +131,8 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
if (isExperienceCritical()) { if (isExperienceCritical()) {
if (player.getMagicalReserves().getEnergy() <= 0.25F) { if (pony.getMagicalReserves().getEnergy() <= 0.25F) {
player.getMagicalReserves().addEnergy(2); pony.getMagicalReserves().addEnergy(2);
} }
if (isRainbooming || (entity.isSneaking() && isRainboom())) { if (isRainbooming || (entity.isSneaking() && isRainboom())) {
@ -209,6 +177,15 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
} }
} }
if (pony.getPhysics().isGravityNegative()) {
entity.onGround = !entity.world.isAir(new BlockPos(entity.getX(), entity.getY() + entity.getHeight() + 0.5F, entity.getZ()));
if (entity.onGround) {
entity.abilities.flying = false;
isFlying = false;
}
}
lastTickPosX = entity.getX(); lastTickPosX = entity.getX();
lastTickPosZ = entity.getZ(); lastTickPosZ = entity.getZ();
@ -216,21 +193,20 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
} }
public SoundEvent getWingSound() { public SoundEvent getWingSound() {
return player.getSpecies() == Race.CHANGELING ? USounds.CHANGELING_BUZZ : USounds.WING_FLAP; return pony.getSpecies() == Race.CHANGELING ? USounds.CHANGELING_BUZZ : USounds.WING_FLAP;
} }
protected void moveFlying(Entity player, MutableVector velocity) { protected void moveFlying(Entity player, MutableVector velocity) {
float forward = 0.000015F * flightExperience * (float)Math.sqrt(getHorizontalMotion(player)); float forward = 0.000015F * flightExperience * (float)Math.sqrt(getHorizontalMotion(player));
int factor = gravity < 0 ? -1 : 1;
boolean sneak = !player.isSneaking(); boolean sneak = !player.isSneaking();
// vertical drop due to gravity // vertical drop due to gravity
if (sneak) { if (sneak) {
velocity.y -= (0.005F - getHorizontalMotion(player) / 100) * factor; velocity.y -= (0.005F - getHorizontalMotion(player) / 100) * getGravitySignum();
} else { } else {
forward += 0.005F; forward += 0.005F;
velocity.y -= 0.0001F * factor; velocity.y -= 0.0001F * getGravitySignum();
} }
velocity.x += - forward * MathHelper.sin(player.yaw * 0.017453292F); velocity.x += - forward * MathHelper.sin(player.yaw * 0.017453292F);
@ -264,7 +240,6 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
forward = 4; forward = 4;
} }
//player.knockBack(player, forward, 1, 1);
velocity.x += - forward * MathHelper.sin((player.yaw + glance) * 0.017453292F); velocity.x += - forward * MathHelper.sin((player.yaw + glance) * 0.017453292F);
velocity.z += forward * MathHelper.cos((player.yaw + glance) * 0.017453292F); velocity.z += forward * MathHelper.cos((player.yaw + glance) * 0.017453292F);
} }
@ -289,8 +264,10 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
flightExperience = Math.max(0, flightExperience + factor * maximumGain / gainSteps); flightExperience = Math.max(0, flightExperience + factor * maximumGain / gainSteps);
} }
public void updateFlightStat(PlayerEntity entity, boolean flying) { public void updateFlightStat(boolean flying) {
entity.abilities.allowFlying = checkCanFly(Pony.of(entity)); PlayerEntity entity = pony.getOwner();
entity.abilities.allowFlying = checkCanFly();
if (entity.abilities.allowFlying) { if (entity.abilities.allowFlying) {
entity.abilities.flying |= flying; entity.abilities.flying |= flying;
@ -308,28 +285,22 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
@Override @Override
public void toNBT(CompoundTag compound) { public void toNBT(CompoundTag compound) {
super.toNBT(compound);
compound.putInt("flightDuration", ticksNextLevel); compound.putInt("flightDuration", ticksNextLevel);
compound.putFloat("flightExperience", flightExperience); compound.putFloat("flightExperience", flightExperience);
compound.putBoolean("isFlying", isFlying); compound.putBoolean("isFlying", isFlying);
compound.putBoolean("isRainbooming", isRainbooming); compound.putBoolean("isRainbooming", isRainbooming);
if (gravity != 0) {
compound.putFloat("gravity", gravity);
}
} }
@Override @Override
public void fromNBT(CompoundTag compound) { public void fromNBT(CompoundTag compound) {
super.fromNBT(compound);
ticksNextLevel = compound.getInt("flightDuration"); ticksNextLevel = compound.getInt("flightDuration");
flightExperience = compound.getFloat("flightExperience"); flightExperience = compound.getFloat("flightExperience");
isFlying = compound.getBoolean("isFlying"); isFlying = compound.getBoolean("isFlying");
isRainbooming = compound.getBoolean("isRainbooming"); isRainbooming = compound.getBoolean("isRainbooming");
if (compound.contains("gravity")) { pony.getOwner().calculateDimensions();
gravity = compound.getFloat("gravity");
} else {
gravity = 0;
}
} }
@Override @Override

View file

@ -3,111 +3,422 @@ package com.minelittlepony.unicopia.entity.player;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.ducks.PonyContainer; import com.minelittlepony.unicopia.ducks.PonyContainer;
import com.minelittlepony.unicopia.enchanting.PageOwner; import com.minelittlepony.unicopia.enchanting.PageOwner;
import com.minelittlepony.unicopia.entity.FlightControl; import com.minelittlepony.unicopia.entity.Physics;
import com.minelittlepony.unicopia.entity.RaceContainer; import com.minelittlepony.unicopia.entity.Ponylike;
import com.minelittlepony.unicopia.entity.Trap;
import com.minelittlepony.unicopia.magic.Affinity;
import com.minelittlepony.unicopia.magic.AttachedMagicEffect;
import com.minelittlepony.unicopia.magic.Caster; import com.minelittlepony.unicopia.magic.Caster;
import com.minelittlepony.unicopia.magic.HeldMagicEffect;
import com.minelittlepony.unicopia.magic.MagicEffect;
import com.minelittlepony.unicopia.magic.MagicalItem;
import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.EffectSync;
import com.minelittlepony.unicopia.network.MsgPlayerCapabilities;
import com.minelittlepony.unicopia.network.Transmittable; import com.minelittlepony.unicopia.network.Transmittable;
import com.minelittlepony.unicopia.toxin.Toxicity;
import com.minelittlepony.unicopia.toxin.Toxin;
import com.minelittlepony.util.BasicEasingInterpolator;
import com.minelittlepony.util.IInterpolator; import com.minelittlepony.util.IInterpolator;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import net.minecraft.client.network.packet.EntityPassengersSetS2CPacket;
import net.minecraft.entity.Entity;
import net.minecraft.entity.damage.DamageSource;
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.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerEntity.SleepFailureReason;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Hand;
import net.minecraft.util.Unit; import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
/** public class Pony implements Caster<PlayerEntity>, Ponylike<PlayerEntity>, Transmittable {
* The player.
*
* This is the core of unicopia.
*/
public interface Pony extends Caster<PlayerEntity>, RaceContainer<PlayerEntity>, Transmittable {
/** private static final TrackedData<Integer> RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER);
* Gets the player's magical abilities delegate responsible for all spell casting and persisting/updating. static final TrackedData<Float> ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
*/ static final TrackedData<Float> EXERTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
AbilityDispatcher getAbilities(); private static final TrackedData<CompoundTag> EFFECT = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.TAG_COMPOUND);
private static final TrackedData<CompoundTag> HELD_EFFECT = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.TAG_COMPOUND);
/** private final PlayerPageStats pageStates = new PlayerPageStats(this);
* Gets the gravity delegate responsible for updating flight states private final AbilityDispatcher powers = new AbilityDispatcher(this);
*/ private final PlayerPhysics gravity = new PlayerPhysics(this);
GravityDelegate getGravity(); private final PlayerAttributes attributes = new PlayerAttributes();
private final PlayerCamera camera = new PlayerCamera(this);
private final PlayerInventory inventory = new PlayerInventory(this);
private final MagicReserves mana;
/** private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
* Gets the flight delegate. private final EffectSync heldEffectDelegate = new EffectSync(this, HELD_EFFECT);
*/
FlightControl getFlight();
/** private final IInterpolator interpolator = new BasicEasingInterpolator();
* Gets the player's viewport.
*/
PlayerCamera getCamera();
MagicReserves getMagicalReserves(); private float nextStepDistance = 1;
/** private final PlayerEntity entity;
* Gets the inventory delegate for this player.
*/
PlayerInventory getInventory();
/** private boolean dirty = false;
* Gets an animation interpolator.
*/
IInterpolator getInterpolator();
PageOwner getPages(); private boolean invisible = false;
/** public Pony(PlayerEntity player) {
*/ this.entity = player;
float getExtendedReach(); this.mana = new ManaContainer(this);
void copyFrom(Pony oldPlayer); player.getDataTracker().startTracking(RACE, Race.EARTH.ordinal());
player.getDataTracker().startTracking(EFFECT, new CompoundTag());
player.getDataTracker().startTracking(HELD_EFFECT, new CompoundTag());
/** player.getAttributes().register(PlayerAttributes.EXTENDED_REACH_DISTANCE);
* Called when the player steps on clouds. }
*/
boolean stepOnCloud();
/** @Override
* Called when this player falls. public Race getSpecies() {
*/ if (getOwner() == null) {
float onImpact(float distance); return Race.HUMAN;
}
/** return Race.fromId(getOwner().getDataTracker().get(RACE));
* Called whenever the player eats something. }
*/
void onEat(ItemStack food);
/** @Override
* Attempts to sleep in a bed. public void setSpecies(Race race) {
* race = race.validate(entity);
* @param pos The position of the bed
*
* @return The sleep result.
*/
Either<PlayerEntity.SleepFailureReason, Unit> trySleep(BlockPos pos);
/** entity.getDataTracker().set(RACE, race.ordinal());
* Returns true if this player is the use.
*/ gravity.updateFlightStat(entity.abilities.flying);
default boolean isClientPlayer() { entity.sendAbilitiesUpdate();
}
public MagicReserves getMagicalReserves() {
return mana;
}
@Override
public boolean isInvisible() {
return invisible && hasEffect();
}
@Override
public void setInvisible(boolean invisible) {
this.invisible = invisible;
}
@Nullable
public HeldMagicEffect getHeldEffect(ItemStack stack) {
if (!getSpecies().canCast()) {
heldEffectDelegate.set(null);
return null;
}
HeldMagicEffect heldEffect = heldEffectDelegate.get(HeldMagicEffect.class, true);
if (heldEffect == null || !heldEffect.getName().equals(SpellRegistry.getKeyFromStack(stack))) {
heldEffect = SpellRegistry.instance().getHeldFrom(stack);
heldEffectDelegate.set(heldEffect);
}
return heldEffect;
}
@Override
public Affinity getAffinity() {
return Affinity.NEUTRAL;
}
public void setDirty() {
dirty = true;
}
@Override
public void sendCapabilities(boolean full) {
dirty = false;
if (entity instanceof ServerPlayerEntity) {
System.out.println("Sending capabilities for player");
Channel.BROADCAST_CAPABILITIES.send(new MsgPlayerCapabilities(full, this));
}
}
public AbilityDispatcher getAbilities() {
return powers;
}
public PageOwner getPages() {
return pageStates;
}
@Override
public Physics getPhysics() {
return gravity;
}
public float getExtendedReach() {
return (float)entity.getAttributeInstance(PlayerAttributes.EXTENDED_REACH_DISTANCE).getValue();
}
public Motion getMotion() {
return gravity;
}
public PlayerCamera getCamera() {
return camera;
}
public IInterpolator getInterpolator() {
return interpolator;
}
@Override
public boolean beforeUpdate() {
if (entity.world.isClient()) {
if (entity.hasVehicle() && entity.isSneaking()) {
Entity ridee = entity.getVehicle();
if (ridee instanceof Trap) {
if (((Trap)ridee).attemptDismount(entity)) {
entity.stopRiding();
} else {
entity.setSneaking(false);
}
} else {
entity.stopRiding();
if (ridee instanceof ServerPlayerEntity) {
((ServerPlayerEntity)ridee).networkHandler.sendPacket(new EntityPassengersSetS2CPacket(ridee));
}
}
}
}
powers.tick();
inventory.tick();
return false;
}
@Override
public void tick() {
gravity.tick();
if (hasEffect()) {
AttachedMagicEffect effect = getEffect(AttachedMagicEffect.class, true);
if (effect != null) {
if (entity.getEntityWorld().isClient()) {
effect.renderOnPerson(this);
}
if (!effect.updateOnPerson(this)) {
setEffect(null);
}
}
}
ItemStack stack = entity.getStackInHand(Hand.MAIN_HAND);
HeldMagicEffect effect = getHeldEffect(stack);
if (effect != null) {
Affinity affinity = stack.getItem() instanceof MagicalItem ? ((MagicalItem)stack.getItem()).getAffinity(stack) : Affinity.NEUTRAL;
effect.updateInHand(this, affinity);
}
mana.addExertion(-1);
mana.addEnergy(-1);
attributes.applyAttributes(entity, getSpecies());
if (dirty) {
sendCapabilities(true);
}
}
public float onImpact(float distance) {
if (getSpecies().canFly()) {
distance = Math.max(0, distance - 5);
}
return distance;
}
@Override
public void onJump() {
if (gravity.isGravityNegative()) {
Vec3d velocity = entity.getVelocity();
entity.setVelocity(velocity.x, velocity.y * -1, velocity.z);
}
}
@Override
public boolean onProjectileImpact(ProjectileEntity projectile) {
if (hasEffect()) {
MagicEffect effect = getEffect();
if (!effect.isDead() && effect.handleProjectileImpact(projectile)) {
return true;
}
}
return false;
}
@Override
public boolean subtractEnergyCost(double foodSubtract) {
if (!entity.abilities.creativeMode) {
int food = (int)(entity.getHungerManager().getFoodLevel() - foodSubtract);
if (food < 0) {
entity.getHungerManager().add(-entity.getHungerManager().getFoodLevel(), 0);
entity.damage(DamageSource.MAGIC, -food/2);
} else {
entity.getHungerManager().add((int)-foodSubtract, 0);
}
}
return entity.getHealth() > 0;
}
public boolean stepOnCloud() {
if (entity.fallDistance > 1 || entity.distanceTraveled > nextStepDistance) {
nextStepDistance = entity.distanceTraveled + 2;
entity.fallDistance = 0;
return true;
}
return false;
}
public Either<SleepFailureReason, Unit> trySleep(BlockPos pos) {
if (getInventory().matches(UTags.CURSED_ARTEFACTS)) {
if (!isClient()) {
entity.addChatMessage(new TranslatableText("tile.bed.youAreAMonster"), true);
}
return Either.left(SleepFailureReason.OTHER_PROBLEM);
}
if (findAllSpellsInRange(10).anyMatch(c -> c instanceof Pony && ((Pony)c).getInventory().matches(UTags.CURSED_ARTEFACTS))) {
return Either.left(SleepFailureReason.NOT_SAFE);
}
return Either.right(Unit.INSTANCE);
}
public PlayerInventory getInventory() {
return inventory;
}
public void onEat(ItemStack stack) {
if (getSpecies() == Race.CHANGELING) {
Toxin.POISON.afflict(getOwner(), Toxicity.SAFE, stack);
}
}
@Override
public void toNBT(CompoundTag compound) {
compound.putString("playerSpecies", getSpecies().name());
compound.put("powers", powers.toNBT());
compound.put("gravity", gravity.toNBT());
MagicEffect effect = getEffect();
if (effect != null) {
compound.put("effect", SpellRegistry.instance().serializeEffectToNBT(effect));
}
pageStates.toNBT(compound);
}
@Override
public void fromNBT(CompoundTag compound) {
setSpecies(Race.fromName(compound.getString("playerSpecies")));
powers.fromNBT(compound.getCompound("powers"));
gravity.fromNBT(compound.getCompound("gravity"));
if (compound.contains("effect")) {
effectDelegate.set(SpellRegistry.instance().createEffectFromNBT(compound.getCompound("effect")));
}
pageStates.fromNBT(compound);
}
public void copyFrom(Pony oldPlayer) {
setEffect(oldPlayer.getEffect());
setSpecies(oldPlayer.getSpecies());
setDirty();
}
@Override
public void setEffect(@Nullable MagicEffect effect) {
effectDelegate.set(effect);
setDirty();
}
@Override
public boolean hasEffect() {
return effectDelegate.has();
}
@Nullable
@Override
public <T extends MagicEffect> T getEffect(@Nullable Class<T> type, boolean update) {
return effectDelegate.get(type, update);
}
@Override
public void setOwner(PlayerEntity owner) {
}
@Override
public PlayerEntity getOwner() {
return entity;
}
@Override
public int getCurrentLevel() {
return 0;
}
@Override
public void setCurrentLevel(int level) {
}
public boolean isClientPlayer() {
return InteractionManager.instance().isClientPlayer(getOwner()); return InteractionManager.instance().isClientPlayer(getOwner());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
static Pony of(@Nullable PlayerEntity player) { public static Pony of(@Nullable PlayerEntity player) {
return player == null ? null : ((PonyContainer<Pony>)player).get(); return player == null ? null : ((PonyContainer<Pony>)player).get();
} }
static boolean equal(GameProfile one, GameProfile two) { public static boolean equal(GameProfile one, GameProfile two) {
return one == two || (one != null && two != null && one.getId().equals(two.getId())); return one == two || (one != null && two != null && one.getId().equals(two.getId()));
} }
static boolean equal(PlayerEntity one, PlayerEntity two) { public static boolean equal(PlayerEntity one, PlayerEntity two) {
return one == two || (one != null && two != null && equal(one.getGameProfile(), two.getGameProfile())); return one == two || (one != null && two != null && equal(one.getGameProfile(), two.getGameProfile()));
} }
} }

View file

@ -8,7 +8,7 @@ import javax.annotation.Nullable;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.minelittlepony.unicopia.AwaitTickQueue; import com.minelittlepony.unicopia.AwaitTickQueue;
import com.minelittlepony.unicopia.ducks.IItemEntity; import com.minelittlepony.unicopia.ducks.IItemEntity;
import com.minelittlepony.unicopia.entity.ItemEntityCapabilities; import com.minelittlepony.unicopia.entity.ItemImpl;
import com.minelittlepony.unicopia.entity.player.MagicReserves; import com.minelittlepony.unicopia.entity.player.MagicReserves;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.magic.Affinity; import com.minelittlepony.unicopia.magic.Affinity;
@ -48,7 +48,7 @@ import net.minecraft.world.LocalDifficulty;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.explosion.Explosion.DestructionType; import net.minecraft.world.explosion.Explosion.DestructionType;
public class AlicornAmuletItem extends ArmorItem implements AddictiveMagicalItem, ItemEntityCapabilities.TickableItem { public class AlicornAmuletItem extends ArmorItem implements AddictiveMagicalItem, ItemImpl.TickableItem {
private static final UUID[] MODIFIERS = new UUID[] { private static final UUID[] MODIFIERS = new UUID[] {
UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"),

View file

@ -4,7 +4,7 @@ import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ducks.IItemEntity; import com.minelittlepony.unicopia.ducks.IItemEntity;
import com.minelittlepony.unicopia.entity.ItemEntityCapabilities; import com.minelittlepony.unicopia.entity.ItemImpl;
import com.minelittlepony.unicopia.toxin.Toxicity; import com.minelittlepony.unicopia.toxin.Toxicity;
import net.minecraft.client.item.TooltipContext; import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
@ -17,7 +17,7 @@ import net.minecraft.util.ActionResult;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
public class AppleItem extends Item implements ItemEntityCapabilities.TickableItem { public class AppleItem extends Item implements ItemImpl.TickableItem {
public AppleItem(Settings settings) { public AppleItem(Settings settings) {
super(settings); super(settings);

View file

@ -19,7 +19,7 @@ public interface Useable {
* *
* @param stack The current itemstack * @param stack The current itemstack
* @param affinity The affinity of the casting artifact * @param affinity The affinity of the casting artifact
* @param player The player * @param pony The player
* @param world The player's world * @param world The player's world
* @param pos The location clicked * @param pos The location clicked
* @param side The side of the block clicked * @param side The side of the block clicked

View file

@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.ducks.IItemEntity; import com.minelittlepony.unicopia.ducks.IItemEntity;
import com.minelittlepony.unicopia.entity.ItemEntityCapabilities; import com.minelittlepony.unicopia.entity.ItemImpl;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity; import net.minecraft.entity.ItemEntity;
@ -16,17 +16,17 @@ import net.minecraft.nbt.CompoundTag;
@Mixin(ItemEntity.class) @Mixin(ItemEntity.class)
abstract class MixinItemEntity extends Entity implements IItemEntity { abstract class MixinItemEntity extends Entity implements IItemEntity {
private ItemEntityCapabilities caster; private ItemImpl caster;
private MixinItemEntity() { super(null, null); } private MixinItemEntity() { super(null, null); }
@Override @Override
public ItemEntityCapabilities create() { public ItemImpl create() {
return new ItemEntityCapabilities((ItemEntity)(Object)this); return new ItemImpl((ItemEntity)(Object)this);
} }
@Override @Override
public ItemEntityCapabilities get() { public ItemImpl get() {
if (caster == null) { if (caster == null) {
caster = create(); caster = create();
} }
@ -42,7 +42,7 @@ abstract class MixinItemEntity extends Entity implements IItemEntity {
@Inject(method = "tick()V", at = @At("RETURN")) @Inject(method = "tick()V", at = @At("RETURN"))
private void afterTick(CallbackInfo info) { private void afterTick(CallbackInfo info) {
get().onUpdate(); get().tick();
} }
@Inject(method = "writeCustomDataToTag(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("HEAD")) @Inject(method = "writeCustomDataToTag(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("HEAD"))

View file

@ -2,32 +2,35 @@ package com.minelittlepony.unicopia.mixin;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.ducks.PonyContainer; import com.minelittlepony.unicopia.ducks.PonyContainer;
import com.minelittlepony.unicopia.entity.Ponylike; import com.minelittlepony.unicopia.entity.Ponylike;
import com.minelittlepony.unicopia.entity.LivingEntityCapabilities; import com.minelittlepony.unicopia.entity.Creature;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.math.BlockPos;
@Mixin(LivingEntity.class) @Mixin(LivingEntity.class)
abstract class MixinLivingEntity extends Entity implements PonyContainer<Ponylike> { abstract class MixinLivingEntity extends Entity implements PonyContainer<Ponylike<?>> {
private Ponylike caster; private Ponylike<?> caster;
private MixinLivingEntity() { super(null, null); } private MixinLivingEntity() { super(null, null); }
@Override @Override
public Ponylike create() { public Ponylike<?> create() {
return new LivingEntityCapabilities((LivingEntity)(Object)this); return new Creature((LivingEntity)(Object)this);
} }
@Override @Override
public Ponylike get() { public Ponylike<?> get() {
if (caster == null) { if (caster == null) {
caster = create(); caster = create();
} }
@ -55,12 +58,12 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Ponylik
@Inject(method = "tick()V", at = @At("RETURN")) @Inject(method = "tick()V", at = @At("RETURN"))
private void afterTick(CallbackInfo info) { private void afterTick(CallbackInfo info) {
get().onUpdate(); get().tick();
} }
@Inject(method = "<clinit>()V", at = @At("RETURN"), remap = false) @Inject(method = "<clinit>()V", at = @At("RETURN"), remap = false)
private static void clinit(CallbackInfo info) { private static void clinit(CallbackInfo info) {
LivingEntityCapabilities.boostrap(); Creature.boostrap();
} }
@Inject(method = "writeCustomDataToTag(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("HEAD")) @Inject(method = "writeCustomDataToTag(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("HEAD"))
@ -75,6 +78,31 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Ponylik
} }
} }
@ModifyConstant(method = "travel(Lnet/minecraft/util/math/Vec3d;)V", constant = {
@Constant(doubleValue = 0.08D),
@Constant(doubleValue = 0.01D)
})
private double modifyGravity(double initial) {
return get().getPhysics().calcGravity(initial);
}
@Override
protected BlockPos getLandingPos() {
if (get().getPhysics().isGravityNegative()) {
return get().getPhysics().getHeadPosition();
}
return super.getLandingPos();
}
@Override
protected void spawnSprintingParticles() {
if (get().getPhysics().isGravityNegative()) {
get().getPhysics().spawnSprintingParticles();
} else {
super.spawnSprintingParticles();
}
}
// ---------- temporary // ---------- temporary
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@Inject(method = "isClimbing()Z", at = @At("HEAD"), cancellable = true) @Inject(method = "isClimbing()Z", at = @At("HEAD"), cancellable = true)

View file

@ -10,7 +10,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.ducks.PonyContainer; import com.minelittlepony.unicopia.ducks.PonyContainer;
import com.minelittlepony.unicopia.entity.Ponylike; import com.minelittlepony.unicopia.entity.Ponylike;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.entity.player.PlayerImpl;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityDimensions;
@ -29,8 +28,8 @@ abstract class MixinPlayerEntity extends LivingEntity implements PonyContainer<P
private MixinPlayerEntity() { super(null, null); } private MixinPlayerEntity() { super(null, null); }
@Override @Override
public Ponylike create() { public Ponylike<?> create() {
return new PlayerImpl((PlayerEntity)(Object)this); return new Pony((PlayerEntity)(Object)this);
} }
@ModifyVariable(method = "handleFallDamage(FF)Z", @ModifyVariable(method = "handleFallDamage(FF)Z",
@ -72,20 +71,20 @@ abstract class MixinPlayerEntity extends LivingEntity implements PonyContainer<P
at = @At("RETURN")) at = @At("RETURN"))
private void onSetGameMode(GameMode mode, CallbackInfo info) { private void onSetGameMode(GameMode mode, CallbackInfo info) {
get().setSpecies(get().getSpecies()); get().setSpecies(get().getSpecies());
get().sendCapabilities(true); get().setDirty();
} }
@Inject(method = "getActiveEyeHeight(Lnet/minecraft/entity/EntityPose;Lnet/minecraft/entity/EntityDimensions;)F", @Inject(method = "getActiveEyeHeight(Lnet/minecraft/entity/EntityPose;Lnet/minecraft/entity/EntityDimensions;)F",
at = @At("RETURN"), at = @At("RETURN"),
cancellable = true) cancellable = true)
private void onGetActiveEyeHeight(EntityPose pose, EntityDimensions dimensions, CallbackInfoReturnable<Float> info) { private void onGetActiveEyeHeight(EntityPose pose, EntityDimensions dimensions, CallbackInfoReturnable<Float> info) {
info.setReturnValue(get().getGravity().getDimensions().getActiveEyeHeight(info.getReturnValue())); info.setReturnValue(get().getMotion().getDimensions().getActiveEyeHeight(info.getReturnValue()));
} }
@Inject(method = "getDimensions(Lnet/minecraft/entity/EntityPose;)Lnet/minecraft/entity/EntityDimensions;", @Inject(method = "getDimensions(Lnet/minecraft/entity/EntityPose;)Lnet/minecraft/entity/EntityDimensions;",
at = @At("RETURN"), at = @At("RETURN"),
cancellable = true) cancellable = true)
public void onGetDimensions(EntityPose pose, CallbackInfoReturnable<EntityDimensions> info) { public void onGetDimensions(EntityPose pose, CallbackInfoReturnable<EntityDimensions> info) {
info.setReturnValue(get().getGravity().getDimensions().getDimensions(pose, info.getReturnValue())); info.setReturnValue(get().getMotion().getDimensions().getDimensions(pose, info.getReturnValue()));
} }
} }

View file

@ -2,15 +2,11 @@ package com.minelittlepony.unicopia.mixin.client;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@Mixin(Camera.class) @Mixin(Camera.class)
@ -42,18 +38,4 @@ abstract class MixinCamera {
return pitch; return pitch;
} }
@Inject(method = "setRotation(FF)V",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/util/math/Quaternion;set(FFFF)V",
shift = Shift.AFTER)
)
private void onSetRotation(float yaw, float pitch, CallbackInfo info) {
PlayerEntity player = MinecraftClient.getInstance().player;
if (player != null && MinecraftClient.getInstance().cameraEntity == player) {
float roll = Pony.of(player).getCamera().calculateRoll();
((Camera)(Object)this).getRotation().hamiltonProduct(Vector3f.POSITIVE_Z.getDegreesQuaternion(roll));
}
}
} }

View file

@ -5,6 +5,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.client.render.WorldRenderDelegate;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.magic.spell.DisguiseSpell; import com.minelittlepony.unicopia.magic.spell.DisguiseSpell;
@ -31,13 +32,7 @@ abstract class MixinEntityRenderDispatcher {
Pony pony = Pony.of((PlayerEntity)entity); Pony pony = Pony.of((PlayerEntity)entity);
if (pony.getGravity().getGravitationConstant() < 0) { WorldRenderDelegate.INSTANCE.beforeEntityRender(pony, matrices, x, y, z);
matrices.push();
matrices.translate(0, entity.getDimensions(entity.getPose()).height, 0);
matrices.scale(1, -1, 1);
entity.prevPitch *= -1;
entity.pitch *= -1;
}
DisguiseSpell effect = pony.getEffect(DisguiseSpell.class, true); DisguiseSpell effect = pony.getEffect(DisguiseSpell.class, true);
@ -64,19 +59,13 @@ abstract class MixinEntityRenderDispatcher {
} }
} }
@Inject(method = RENDER, at = @At("HEAD")) @Inject(method = RENDER, at = @At("RETURN"))
private <E extends Entity> void afterRender(E entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo info) { private <E extends Entity> void afterRender(E entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo info) {
if (!(entity instanceof PlayerEntity)) { if (!(entity instanceof PlayerEntity)) {
return; return;
} }
Pony pony = Pony.of((PlayerEntity)entity); WorldRenderDelegate.INSTANCE.afterEntityRender(Pony.of((PlayerEntity)entity), matrices);
if (pony.getGravity().getGravitationConstant() < 0) {
matrices.pop();
entity.prevPitch *= -1;
entity.pitch *= -1;
}
} }
} }

View file

@ -3,13 +3,16 @@ package com.minelittlepony.unicopia.mixin.client;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.client.render.WorldRenderDelegate;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
import net.minecraft.client.render.GameRenderer; import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.resource.SynchronousResourceReloadListener; import net.minecraft.resource.SynchronousResourceReloadListener;
@Mixin(GameRenderer.class) @Mixin(GameRenderer.class)
@ -22,4 +25,10 @@ abstract class MixinGameRenderer implements AutoCloseable, SynchronousResourceRe
.getCamera() .getCamera()
.calculateFieldOfView(info.getReturnValue())); .calculateFieldOfView(info.getReturnValue()));
} }
@Inject(method = "renderWorld(FLLnet/minecraft/client/util/math/MatrixStack;)V",
at = @At("HEAD"))
public void onRenderWorld(float tickDelta, long limitTime, MatrixStack matrices, CallbackInfo info) {
WorldRenderDelegate.INSTANCE.applyWorldTransform(matrices, tickDelta);
}
} }

View file

@ -17,7 +17,7 @@ abstract class MixinKeyboardInput extends Input {
private void onTick(boolean strafe, CallbackInfo info) { private void onTick(boolean strafe, CallbackInfo info) {
Pony player = Pony.of(MinecraftClient.getInstance().player); Pony player = Pony.of(MinecraftClient.getInstance().player);
if (player.getGravity().getGravitationConstant() < 0) { if (player.getPhysics().isGravityNegative()) {
boolean tmp = pressingLeft; boolean tmp = pressingLeft;
pressingLeft = pressingRight; pressingLeft = pressingRight;

View file

@ -21,7 +21,7 @@ abstract class MixinMouse {
@Inject(method = "updateMouse()V", at = @At("HEAD")) @Inject(method = "updateMouse()V", at = @At("HEAD"))
private void onUpdateMouse(CallbackInfo info) { private void onUpdateMouse(CallbackInfo info) {
Pony player = Pony.of(MinecraftClient.getInstance().player); Pony player = Pony.of(MinecraftClient.getInstance().player);
if (player != null&& player.getGravity().getGravitationConstant() < 0) { if (player != null&& player.getPhysics().isGravityNegative()) {
cursorDeltaX = -cursorDeltaX; cursorDeltaX = -cursorDeltaX;
cursorDeltaY = -cursorDeltaY; cursorDeltaY = -cursorDeltaY;
} }