Better drowning physics - custom gas blocks count as 'air' now.

This commit is contained in:
UnknownShadow200 2017-07-01 17:04:00 +10:00
parent 55953c1118
commit 73bb41b64b
2 changed files with 71 additions and 76 deletions

View File

@ -346,10 +346,15 @@ namespace MCGalaxy {
try {
Vec3U16 P = (Vec3U16)pos.BlockCoords;
AABB bb = ModelBB.OffsetPosition(Pos);
if (level.Config.SurvivalDeath) CheckSurvival(P.X, P.Y, P.Z, bb);
int index = level.PosToInt(P.X, P.Y, P.Z);
if (level.Config.SurvivalDeath) {
if (index != oldIndex) PlayerPhysics.Fall(this, bb);
PlayerPhysics.Drown(this, bb);
}
CheckBlock(bb);
oldIndex = level.PosToInt(P.X, P.Y, P.Z);
PlayerPhysics.Walkthrough(this, bb);
oldIndex = index;
} catch (Exception ex) {
Logger.LogError(ex);
}
@ -357,74 +362,6 @@ namespace MCGalaxy {
bool Moved() { return lastRot.RotY != Rot.RotY || lastRot.HeadX != Rot.HeadX; }
void CheckSurvival(ushort x, ushort y, ushort z, AABB bb) {
byte bHead = GetSurvivalBlock(x, y, z);
if (level.PosToInt(x, y, z) != oldIndex) PlayerPhysics.Fall(this, bb);
switch (Block.Convert(bHead)) {
case Block.water:
case Block.waterstill:
case Block.lava:
case Block.lavastill:
fallCount = 0;
drownCount++;
// level drown is in 10ths of a second, and there are 100 ticks/second
if (drownCount > level.Config.DrownTime * 10) {
HandleDeath((ExtBlock)Block.water);
drownCount = 0;
}
break;
case Block.air:
drownCount = 0;
break;
default:
fallCount = 0;
drownCount = 0;
break;
}
}
byte GetSurvivalBlock(ushort x, ushort y, ushort z) {
if (y >= ushort.MaxValue - 512) return Block.blackrock;
if (y >= level.Height) return Block.air;
return level.GetTile(x, y, z);
}
void CheckBlock(AABB bb) {
Vec3S32 min = bb.BlockMin, max = bb.BlockMax;
bool hitWalkthrough = false;
for (int y = min.Y; y <= max.Y; y++)
for (int z = min.Z; z <= max.Z; z++)
for (int x = min.X; x <= max.X; x++)
{
ushort xP = (ushort)x, yP = (ushort)y, zP = (ushort)z;
ExtBlock block = level.GetBlock(xP, yP, zP);
if (block.BlockID == Block.Invalid) continue;
AABB blockBB = level.blockAABBs[block.Index].Offset(x * 32, y * 32, z * 32);
if (!bb.Intersects(blockBB)) continue;
// We can activate only one walkthrough block per movement
if (!hitWalkthrough) {
HandleWalkthrough handler = level.walkthroughHandlers[block.Index];
if (handler != null && handler(this, block, xP, yP, zP)) {
lastWalkthrough = level.PosToInt(xP, yP, zP);
hitWalkthrough = true;
}
}
// Some blocks will cause death of players
if (!level.BlockProps[block.Index].KillerBlock) continue;
if (block.BlockID == Block.tntexplosion && PlayingTntWars) continue; // TODO: hardcoded behaviour is icky
if (block.BlockID == Block.train && trainInvincible) continue;
HandleDeath(block);
}
if (!hitWalkthrough) lastWalkthrough = -1;
}
[Obsolete("Use HandleDeath with ExtBlock attribute")]
public void HandleDeath(byte b, string customMessage = "", bool explode = false, bool immediate = false) {
HandleDeath((ExtBlock)b, customMessage, explode, immediate);

View File

@ -21,13 +21,44 @@ using MCGalaxy.Maths;
namespace MCGalaxy.Blocks.Physics {
internal static class PlayerPhysics {
internal static void Walkthrough(Player p, AABB bb) {
Vec3S32 min = bb.BlockMin, max = bb.BlockMax;
bool hitWalkthrough = false;
for (int y = min.Y; y <= max.Y; y++)
for (int z = min.Z; z <= max.Z; z++)
for (int x = min.X; x <= max.X; x++)
{
ushort xP = (ushort)x, yP = (ushort)y, zP = (ushort)z;
ExtBlock block = p.level.GetBlock(xP, yP, zP);
if (block.BlockID == Block.Invalid) continue;
AABB blockBB = p.level.blockAABBs[block.Index].Offset(x * 32, y * 32, z * 32);
if (!bb.Intersects(blockBB)) continue;
// We can activate only one walkthrough block per movement
if (!hitWalkthrough) {
HandleWalkthrough handler = p.level.walkthroughHandlers[block.Index];
if (handler != null && handler(p, block, xP, yP, zP)) {
p.lastWalkthrough = p.level.PosToInt(xP, yP, zP);
hitWalkthrough = true;
}
}
// Some blocks will cause death of players
if (!p.level.BlockProps[block.Index].KillerBlock) continue;
if (block.BlockID == Block.tntexplosion && p.PlayingTntWars) continue; // TODO: hardcoded behaviour is icky
if (block.BlockID == Block.train && p.trainInvincible) continue;
p.HandleDeath(block);
}
if (!hitWalkthrough) p.lastWalkthrough = -1;
}
internal static void Fall(Player p, AABB bb) {
bb.Min.Y -= 2; // test block below player feet
Vec3S32 min = bb.BlockMin;
if (min.Y == p.oldFallY) return;
Vec3S32 max = bb.BlockMax;
Vec3S32 min = bb.BlockMin, max = bb.BlockMax;
bool allGas = true;
for (int z = min.Z; z <= max.Z; z++)
@ -54,6 +85,33 @@ namespace MCGalaxy.Blocks.Physics {
p.drownCount = 0;
}
internal static void Drown(Player p, AABB bb) {
Vec3S32 P = bb.Max;
ExtBlock bHead = GetSurvivalBlock(p, (ushort)P.X, (ushort)P.Y, (ushort)P.Z);
if (bHead.IsPhysicsType) bHead.BlockID = Block.Convert(bHead.BlockID);
switch (bHead.BlockID) {
case Block.water:
case Block.waterstill:
case Block.lava:
case Block.lavastill:
p.fallCount = 0;
p.drownCount++;
// level drown is in 10ths of a second, and there are 100 ticks/second
if (p.drownCount > p.level.Config.DrownTime * 10) {
p.HandleDeath((ExtBlock)Block.water);
p.drownCount = 0;
}
break;
default:
bool isGas = p.level.CollideType(bHead) == CollideType.WalkThrough;
if (!isGas) p.fallCount = 0;
p.drownCount = 0;
break;
}
}
static ExtBlock GetSurvivalBlock(Player p, int x, int y, int z) {
if (y < 0) return (ExtBlock)Block.blackrock;
if (y >= p.level.Height) return ExtBlock.Air;