From 73bb41b64ba565a3beea9537005f927df630cee6 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 1 Jul 2017 17:04:00 +1000 Subject: [PATCH] Better drowning physics - custom gas blocks count as 'air' now. --- MCGalaxy/Player/Player.Handlers.cs | 79 +++--------------------------- MCGalaxy/Player/PlayerPhysics.cs | 68 +++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 76 deletions(-) diff --git a/MCGalaxy/Player/Player.Handlers.cs b/MCGalaxy/Player/Player.Handlers.cs index 481071949..dec26fd81 100644 --- a/MCGalaxy/Player/Player.Handlers.cs +++ b/MCGalaxy/Player/Player.Handlers.cs @@ -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); diff --git a/MCGalaxy/Player/PlayerPhysics.cs b/MCGalaxy/Player/PlayerPhysics.cs index 3cad07713..c59efd703 100644 --- a/MCGalaxy/Player/PlayerPhysics.cs +++ b/MCGalaxy/Player/PlayerPhysics.cs @@ -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;