Super cool entities and fun

- Conductor entities now rotate to face their carts' motion
- Fixed Contraption passengers not visible to clients whenever the seat position offsets them out of ticking chunks just after loading in
This commit is contained in:
simibubi 2022-03-25 22:40:31 +01:00
parent 273a276fda
commit 9d8803d280
5 changed files with 82 additions and 12 deletions

View file

@ -28,6 +28,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.int
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket;
import com.simibubi.create.foundation.collision.Matrix3d;
import com.simibubi.create.foundation.mixin.accessor.ServerLevelAccessor;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.VecHelper;
@ -44,10 +45,13 @@ import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.entity.decoration.HangingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile;
@ -267,7 +271,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
}
@Override
public final void tick() {
public void tick() {
if (contraption == null) {
discard();
return;
@ -287,6 +291,40 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
contraption.onEntityTick(level);
tickContraption();
super.tick();
if (!(level instanceof ServerLevelAccessor sl))
return;
for (Entity entity : getPassengers()) {
if (entity instanceof Player)
continue;
if (entity.isAlwaysTicking())
continue;
if (sl.create$getEntityTickList()
.contains(entity))
continue;
positionRider(entity);
}
}
public void alignPassenger(Entity passenger) {
Vec3 motion = getContactPointMotion(passenger.getEyePosition());
if (Mth.equal(motion.length(), 0))
return;
if (passenger instanceof ArmorStand)
return;
if (!(passenger instanceof LivingEntity living))
return;
float angle = AngleHelper.deg(-Mth.atan2(motion.x, motion.z));
if (level.isClientSide) {
living.lerpTo(0, 0, 0, 0, 0, 0, false);
living.lerpHeadTo(0, 0);
living.setYRot(angle);
living.setXRot(0);
living.yBodyRot = angle;
living.yHeadRot = angle;
} else
living.setYRot(angle);
}
protected abstract void tickContraption();
@ -496,7 +534,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
return;
StructureTransform transform = makeStructureTransform();
contraption.stop(level);
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this),
new ContraptionDisassemblyPacket(this.getId(), transform));
@ -561,9 +599,6 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
@Override
public void onRemovedFromWorld() {
super.onRemovedFromWorld();
if (level != null && level.isClientSide)
return;
getPassengers().forEach(Entity::discard);
}
@Override

View file

@ -20,6 +20,7 @@ import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Entity.RemovalReason;
@ -160,18 +161,21 @@ public class Carriage {
public void createEntity(Level level) {
Entity entity = EntityType.loadEntityRecursive(serialisedEntity, level, e -> {
level.addFreshEntity(e);
e.moveTo(positionAnchor);
return e;
});
if (!(entity instanceof CarriageContraptionEntity cce))
return;
Vec3 pos = positionAnchor;
cce.setPos(pos);
cce.setCarriage(this);
cce.setGraph(train.graph == null ? null : train.graph.id);
cce.setCarriage(this);
cce.syncCarriage();
this.entity = new WeakReference<>(cce);
if (level instanceof ServerLevel sl)
sl.tryAddFreshEntityWithPassengers(entity);
}
public void manageEntity(Level level) {
@ -196,11 +200,13 @@ public class Carriage {
}
private void removeAndSaveEntity(CarriageContraptionEntity entity) {
serialisedEntity = entity.serializeNBT();
for (Entity passenger : entity.getPassengers())
if (!(passenger instanceof Player))
passenger.remove(RemovalReason.UNLOADED_WITH_PLAYER);
serialisedEntity = entity.serializeNBT();
passenger.discard();
entity.discard();
this.entity.clear();
}

View file

@ -124,9 +124,24 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
return entity;
}
@Override
public void tick() {
super.tick();
if (contraption instanceof CarriageContraption cc)
for (Entity entity : getPassengers()) {
BlockPos seatOf = cc.getSeatOf(entity.getUUID());
if (seatOf == null)
continue;
if (cc.conductorSeats.get(seatOf) == null)
continue;
alignPassenger(entity);
}
}
@Override
protected void tickContraption() {
if (!(contraption instanceof CarriageContraption))
if (!(contraption instanceof CarriageContraption cc))
return;
if (carriage == null) {
if (level.isClientSide) {

View file

@ -0,0 +1,13 @@
package com.simibubi.create.foundation.mixin.accessor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.entity.EntityTickList;
@Mixin(ServerLevel.class)
public interface ServerLevelAccessor {
@Accessor("entityTickList")
EntityTickList create$getEntityTickList();
}

View file

@ -9,6 +9,7 @@
"accessor.AbstractProjectileDispenseBehaviorAccessor",
"accessor.DispenserBlockAccessor",
"accessor.FallingBlockEntityAccessor",
"accessor.ServerLevelAccessor",
"accessor.LivingEntityAccessor"
],
"client": [