Casualty Control

- Attempted to reduce false positives for damage from carriage contraptions
This commit is contained in:
simibubi 2022-09-22 18:03:15 +02:00
parent eee9c509e3
commit e6903a733d
4 changed files with 94 additions and 63 deletions

View File

@ -58,6 +58,8 @@ public class BlockBreakingMovementBehaviour implements MovementBehaviour {
continue; continue;
if (entity instanceof AbstractContraptionEntity) if (entity instanceof AbstractContraptionEntity)
continue; continue;
if (entity.isPassengerOfSameVehicle(context.contraption.entity))
continue;
if (entity instanceof AbstractMinecart) if (entity instanceof AbstractMinecart)
for (Entity passenger : entity.getIndirectPassengers()) for (Entity passenger : entity.getIndirectPassengers())
if (passenger instanceof AbstractContraptionEntity if (passenger instanceof AbstractContraptionEntity

View File

@ -140,6 +140,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
return true; return true;
} }
public void registerColliding(Entity collidingEntity) {
collidingEntities.put(collidingEntity, new MutableInt());
}
public void addSittingPassenger(Entity passenger, int seatIndex) { public void addSittingPassenger(Entity passenger, int seatIndex) {
for (Entity entity : getPassengers()) { for (Entity entity : getPassengers()) {
BlockPos seatOf = contraption.getSeatOf(entity.getUUID()); BlockPos seatOf = contraption.getSeatOf(entity.getUUID());

View File

@ -7,7 +7,6 @@ import java.util.List;
import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableFloat; import org.apache.commons.lang3.mutable.MutableFloat;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
@ -88,7 +87,8 @@ public class ContraptionCollider {
if (playerType == PlayerType.REMOTE) if (playerType == PlayerType.REMOTE)
continue; continue;
entity.getSelfAndPassengers().forEach(e -> { entity.getSelfAndPassengers()
.forEach(e -> {
if (e instanceof ServerPlayer) if (e instanceof ServerPlayer)
((ServerPlayer) e).connection.aboveGroundTickCount = 0; ((ServerPlayer) e).connection.aboveGroundTickCount = 0;
}); });
@ -329,50 +329,15 @@ public class ContraptionCollider {
entityPosition.z + allowedMovement.z); entityPosition.z + allowedMovement.z);
entityPosition = entity.position(); entityPosition = entity.position();
if (contraptionEntity instanceof CarriageContraptionEntity cce && entity.isOnGround() entityMotion =
&& !(entity instanceof ItemEntity) && cce.nonDamageTicks == 0 handleDamageFromTrain(world, contraptionEntity, contraptionMotion, entity, entityMotion, playerType);
&& AllConfigs.SERVER.trains.trainsCauseDamage.get()) {
Vec3 diffMotion = contraptionMotion.subtract(entity.getDeltaMovement());
if (diffMotion.length() > 0.35f && contraptionMotion.length() > 0.35f) {
EntityDamageSource pSource = new EntityDamageSource("create.run_over", contraptionEntity);
double damage = diffMotion.length();
if (entity.getClassification(false) == MobCategory.MONSTER)
damage *= 2;
if (!(entity instanceof Player p) || !p.isCreative() && !p.isSpectator()) {
if (playerType == PlayerType.CLIENT) {
AllPackets.channel
.sendToServer(new TrainCollisionPacket((int) (damage * 16), contraptionEntity.getId()));
world.playSound((Player) entity, entity.blockPosition(), SoundEvents.PLAYER_ATTACK_CRIT,
SoundSource.NEUTRAL, 1, .75f);
} else {
entity.hurt(pSource, (int) (damage * 16));
world.playSound(null, entity.blockPosition(), SoundEvents.PLAYER_ATTACK_CRIT,
SoundSource.NEUTRAL, 1, .75f);
if (!entity.isAlive())
contraptionEntity.getControllingPlayer()
.map(world::getPlayerByUUID)
.ifPresent(AllAdvancements.TRAIN_ROADKILL::awardTo);
}
Vec3 added = entityMotion.add(contraptionMotion.multiply(1, 0, 1)
.normalize()
.add(0, .25, 0)
.scale(damage * 4))
.add(diffMotion);
entityMotion = VecHelper.clamp(added, 3);
}
}
}
entity.hurtMarked = true; entity.hurtMarked = true;
Vec3 contactPointMotion = Vec3.ZERO; Vec3 contactPointMotion = Vec3.ZERO;
if (surfaceCollision.isTrue()) { if (surfaceCollision.isTrue()) {
contraptionEntity.registerColliding(entity);
entity.fallDistance = 0; entity.fallDistance = 0;
contraptionEntity.collidingEntities.put(entity, new MutableInt(0));
boolean canWalk = bounce != 0 || slide == 0; boolean canWalk = bounce != 0 || slide == 0;
if (canWalk || !rotation.hasVerticalRotation()) { if (canWalk || !rotation.hasVerticalRotation()) {
if (canWalk) if (canWalk)
@ -401,6 +366,57 @@ public class ContraptionCollider {
} }
private static Vec3 handleDamageFromTrain(Level world, AbstractContraptionEntity contraptionEntity,
Vec3 contraptionMotion, Entity entity, Vec3 entityMotion, PlayerType playerType) {
if (!(contraptionEntity instanceof CarriageContraptionEntity cce))
return entityMotion;
if (!entity.isOnGround())
return entityMotion;
if (cce.collidingEntities.containsKey(entity))
return entityMotion;
if (entity instanceof ItemEntity)
return entityMotion;
if (cce.nonDamageTicks != 0)
return entityMotion;
if (!AllConfigs.SERVER.trains.trainsCauseDamage.get())
return entityMotion;
Vec3 diffMotion = contraptionMotion.subtract(entity.getDeltaMovement());
if (diffMotion.length() <= 0.35f || contraptionMotion.length() <= 0.35f)
return entityMotion;
EntityDamageSource pSource = new EntityDamageSource("create.run_over", contraptionEntity);
double damage = diffMotion.length();
if (entity.getClassification(false) == MobCategory.MONSTER)
damage *= 2;
if (entity instanceof Player p && (p.isCreative() || p.isSpectator()))
return entityMotion;
if (playerType == PlayerType.CLIENT) {
AllPackets.channel.sendToServer(new TrainCollisionPacket((int) (damage * 16), contraptionEntity.getId()));
world.playSound((Player) entity, entity.blockPosition(), SoundEvents.PLAYER_ATTACK_CRIT,
SoundSource.NEUTRAL, 1, .75f);
} else {
entity.hurt(pSource, (int) (damage * 16));
world.playSound(null, entity.blockPosition(), SoundEvents.PLAYER_ATTACK_CRIT, SoundSource.NEUTRAL, 1, .75f);
if (!entity.isAlive())
contraptionEntity.getControllingPlayer()
.map(world::getPlayerByUUID)
.ifPresent(AllAdvancements.TRAIN_ROADKILL::awardTo);
}
Vec3 added = entityMotion.add(contraptionMotion.multiply(1, 0, 1)
.normalize()
.add(0, .25, 0)
.scale(damage * 4))
.add(diffMotion);
return VecHelper.clamp(added, 3);
}
static boolean bounceEntity(Entity entity, Vec3 normal, AbstractContraptionEntity contraption, double factor) { static boolean bounceEntity(Entity entity, Vec3 normal, AbstractContraptionEntity contraption, double factor) {
if (factor == 0) if (factor == 0)
return false; return false;
@ -473,10 +489,10 @@ public class ContraptionCollider {
boolean flag = p_20273_.x != vec3.x; boolean flag = p_20273_.x != vec3.x;
boolean flag1 = p_20273_.y != vec3.y; boolean flag1 = p_20273_.y != vec3.y;
boolean flag2 = p_20273_.z != vec3.z; boolean flag2 = p_20273_.z != vec3.z;
boolean flag3 = e.isOnGround() || flag1 && p_20273_.y < 0.0D; boolean flag3 = flag1 && p_20273_.y < 0.0D;
if (e.getStepHeight() > 0.0F && flag3 && (flag || flag2)) { if (e.getStepHeight() > 0.0F && flag3 && (flag || flag2)) {
Vec3 vec31 = Vec3 vec31 = collideBoundingBox(e, new Vec3(p_20273_.x, (double) e.getStepHeight(), p_20273_.z), aabb,
collideBoundingBox(e, new Vec3(p_20273_.x, (double) e.getStepHeight(), p_20273_.z), aabb, e.level, list); e.level, list);
Vec3 vec32 = collideBoundingBox(e, new Vec3(0.0D, (double) e.getStepHeight(), 0.0D), Vec3 vec32 = collideBoundingBox(e, new Vec3(0.0D, (double) e.getStepHeight(), 0.0D),
aabb.expandTowards(p_20273_.x, 0.0D, p_20273_.z), e.level, list); aabb.expandTowards(p_20273_.x, 0.0D, p_20273_.z), e.level, list);
if (vec32.y < (double) e.getStepHeight()) { if (vec32.y < (double) e.getStepHeight()) {

View File

@ -107,13 +107,18 @@ public abstract class EntityContraptionInteractionMixin extends CapabilityProvid
if (stepped.get()) if (stepped.get())
this.nextStep = this.nextStep(); this.nextStep = this.nextStep();
} }
@Inject(at = @At(value = "TAIL"), method = "move") @Inject(at = @At(value = "TAIL"), method = "move")
private void movementMixin(MoverType mover, Vec3 movement, CallbackInfo ci) { private void movementMixin(MoverType mover, Vec3 movement, CallbackInfo ci) {
if (self.level.isClientSide && !self.isOnGround()) { // involves client-side view bobbing animation on contraptions // involves client-side view bobbing animation on contraptions
if (!self.level.isClientSide)
return;
if (self.isOnGround())
return;
Vec3 worldPos = self.position() Vec3 worldPos = self.position()
.add(0, -0.2, 0); .add(0, -0.2, 0);
boolean onAtLeastOneContraption = getIntersectionContraptionsStream().anyMatch(cEntity -> {
boolean staysOnAtLeastOneContraption = getIntersectionContraptionsStream().anyMatch(cEntity -> {
Vec3 localPos = ContraptionCollider.getWorldToLocalTranslation(worldPos, cEntity); Vec3 localPos = ContraptionCollider.getWorldToLocalTranslation(worldPos, cEntity);
localPos = worldPos.add(localPos); localPos = worldPos.add(localPos);
@ -123,14 +128,18 @@ public abstract class EntityContraptionInteractionMixin extends CapabilityProvid
StructureTemplate.StructureBlockInfo info = contraption.getBlocks() StructureTemplate.StructureBlockInfo info = contraption.getBlocks()
.get(blockPos); .get(blockPos);
return info != null; if (info == null)
return false;
cEntity.registerColliding(self);
return true;
}); });
if (staysOnAtLeastOneContraption) { if (!onAtLeastOneContraption)
return;
self.setOnGround(true); self.setOnGround(true);
} }
}
}
@Inject(method = { "spawnSprintParticle" }, at = @At(value = "TAIL")) @Inject(method = { "spawnSprintParticle" }, at = @At(value = "TAIL"))
private void createRunningParticlesMixin(CallbackInfo ci) { private void createRunningParticlesMixin(CallbackInfo ci) {