diff --git a/ClassicalSharp/Entities/Components/CollisionsComponent.cs b/ClassicalSharp/Entities/Components/CollisionsComponent.cs index 9cf5545fa..3d98fde9b 100644 --- a/ClassicalSharp/Entities/Components/CollisionsComponent.cs +++ b/ClassicalSharp/Entities/Components/CollisionsComponent.cs @@ -30,24 +30,22 @@ namespace ClassicalSharp.Entities { // TODO: test for corner cases, and refactor this. internal void MoveAndWallSlide() { if (entity.Velocity == Vector3.Zero) return; - Vector3 size = entity.Size; - AABB entityBB, entityExtentBB; + AABB entityBB, entityExtentBB; int count = Searcher.FindReachableBlocks(game, entity, out entityBB, out entityExtentBB); - CollideWithReachableBlocks(count, ref size, ref entityBB, ref entityExtentBB); + CollideWithReachableBlocks(count, ref entityBB, ref entityExtentBB); } - void CollideWithReachableBlocks(int count, ref Vector3 size, - ref AABB entityBB, ref AABB entityExtentBB) { + void CollideWithReachableBlocks(int count, ref AABB entityBB, ref AABB extentBB) { // Reset collision detection states bool wasOn = entity.onGround; entity.onGround = false; hitXMin = false; hitYMin = false; hitZMin = false; hitXMax = false; hitYMax = false; hitZMax = false; - AABB blockBB = default(AABB); - Vector3 bPos; - + + AABB blockBB; + Vector3 bPos, size = entity.Size; for (int i = 0; i < count; i++) { // Unpack the block and coordinate data State state = Searcher.stateCache[i]; @@ -63,10 +61,10 @@ namespace ClassicalSharp.Entities { blockBB.Min.X += bPos.X; blockBB.Min.Y += bPos.Y; blockBB.Min.Z += bPos.Z; blockBB.Max = BlockInfo.MaxBB[block]; blockBB.Max.X += bPos.X; blockBB.Max.Y += bPos.Y; blockBB.Max.Z += bPos.Z; - if (!entityExtentBB.Intersects(blockBB)) continue; + if (!extentBB.Intersects(blockBB)) continue; // Recheck time to collide with block (as colliding with blocks modifies this) - float tx = 0, ty = 0, tz = 0; + float tx, ty, tz; Searcher.CalcTime(ref entity.Velocity, ref entityBB, ref blockBB, out tx, out ty, out tz); if (tx > 1 || ty > 1 || tz > 1) Utils.LogDebug("t > 1 in physics calculation.. this shouldn't have happened."); @@ -80,91 +78,84 @@ namespace ClassicalSharp.Entities { // if we have hit the bottom of a block, we need to change the axis we test first. if (!hitYMin) { if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) { - ClipYMax(ref blockBB, ref entityBB, ref entityExtentBB, ref size); + ClipYMax(ref blockBB, ref entityBB, ref extentBB, ref size); } else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) { - ClipYMin(ref blockBB, ref entityBB, ref entityExtentBB, ref size); + ClipYMin(ref blockBB, ref entityBB, ref extentBB, ref size); } else if (finalBB.Min.X + Adjustment >= blockBB.Max.X) { - ClipXMax(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size); + ClipXMax(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size); } else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) { - ClipXMin(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size); + ClipXMin(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size); } else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) { - ClipZMax(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size); + ClipZMax(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size); } else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) { - ClipZMin(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size); + ClipZMin(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size); } continue; } // if flying or falling, test the horizontal axes first. if (finalBB.Min.X + Adjustment >= blockBB.Max.X) { - ClipXMax(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size); + ClipXMax(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size); } else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) { - ClipXMin(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size); + ClipXMin(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size); } else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) { - ClipZMax(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size); + ClipZMax(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size); } else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) { - ClipZMin(ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size); + ClipZMin(ref blockBB, ref entityBB, wasOn, ref finalBB, ref extentBB, ref size); } else if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) { - ClipYMax(ref blockBB, ref entityBB, ref entityExtentBB, ref size); + ClipYMax(ref blockBB, ref entityBB, ref extentBB, ref size); } else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) { - ClipYMin(ref blockBB, ref entityBB, ref entityExtentBB, ref size); + ClipYMin(ref blockBB, ref entityBB, ref extentBB, ref size); } } } - void ClipXMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, - AABB finalBB, ref AABB entityExtentBB, ref Vector3 size) { - if (!wasOn || !DidSlide(blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB)) { + void ClipXMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) { + if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) { entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment; - ClipX(ref size, ref entityBB, ref entityExtentBB); + ClipX(ref size, ref entityBB, ref extentBB); hitXMin = true; } } - void ClipXMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, - AABB finalBB, ref AABB entityExtentBB, ref Vector3 size) { - if (!wasOn || !DidSlide(blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB)) { + void ClipXMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) { + if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) { entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment; - ClipX(ref size, ref entityBB, ref entityExtentBB); + ClipX(ref size, ref entityBB, ref extentBB); hitXMax = true; } } - void ClipZMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, - AABB finalBB, ref AABB entityExtentBB, ref Vector3 size) { - if (!wasOn || !DidSlide(blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB)) { + void ClipZMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) { + if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) { entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment; - ClipZ(ref size, ref entityBB, ref entityExtentBB); + ClipZ(ref size, ref entityBB, ref extentBB); hitZMax = true; } } - void ClipZMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, - AABB finalBB, ref AABB extentBB, ref Vector3 size) { - if (!wasOn || !DidSlide(blockBB, ref size, finalBB, ref entityBB, ref extentBB)) { + void ClipZMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) { + if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) { entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment; ClipZ(ref size, ref entityBB, ref extentBB); hitZMin = true; } } - void ClipYMin(ref AABB blockBB, ref AABB entityBB, - ref AABB extentBB, ref Vector3 size) { + void ClipYMin(ref AABB blockBB, ref AABB entityBB, ref AABB extentBB, ref Vector3 size) { entity.Position.Y = blockBB.Min.Y - size.Y - Adjustment; ClipY(ref size, ref entityBB, ref extentBB); hitYMin = true; } - void ClipYMax(ref AABB blockBB, ref AABB entityBB, - ref AABB extentBB, ref Vector3 size) { + void ClipYMax(ref AABB blockBB, ref AABB entityBB, ref AABB extentBB, ref Vector3 size) { entity.Position.Y = blockBB.Max.Y + Adjustment; entity.onGround = true; ClipY(ref size, ref entityBB, ref extentBB); hitYMax = true; } - bool DidSlide(AABB blockBB, ref Vector3 size, AABB finalBB, - ref AABB entityBB, ref AABB entityExtentBB) { + bool DidSlide(AABB blockBB, ref Vector3 size, ref AABB finalBB, ref AABB entityBB, ref AABB extentBB) { float yDist = blockBB.Max.Y - entityBB.Min.Y; if (yDist > 0 && yDist <= entity.StepSize + 0.01f) { float blockXMin = blockBB.Min.X, blockZMin = blockBB.Min.Z; @@ -173,7 +164,7 @@ namespace ClassicalSharp.Entities { blockBB.Min.Z = Math.Max(blockBB.Min.Z, blockBB.Max.Z - size.Z / 2); blockBB.Max.Z = Math.Min(blockBB.Max.Z, blockZMin + size.Z / 2); - AABB adjBB = finalBB; + AABB adjBB; adjBB.Min.X = Math.Min(finalBB.Min.X, blockBB.Min.X + Adjustment); adjBB.Max.X = Math.Max(finalBB.Max.X, blockBB.Max.X - Adjustment); adjBB.Min.Y = blockBB.Max.Y + Adjustment; @@ -181,11 +172,11 @@ namespace ClassicalSharp.Entities { adjBB.Min.Z = Math.Min(finalBB.Min.Z, blockBB.Min.Z + Adjustment); adjBB.Max.Z = Math.Max(finalBB.Max.Z, blockBB.Max.Z - Adjustment); - if (!CanSlideThrough(ref adjBB)) - return false; + if (!CanSlideThrough(ref adjBB)) return false; + entity.Position.Y = blockBB.Max.Y + Adjustment; entity.onGround = true; - ClipY(ref size, ref entityBB, ref entityExtentBB); + ClipY(ref size, ref entityBB, ref extentBB); return true; } return false; @@ -194,40 +185,38 @@ namespace ClassicalSharp.Entities { bool CanSlideThrough(ref AABB adjFinalBB) { Vector3I bbMin = Vector3I.Floor(adjFinalBB.Min); Vector3I bbMax = Vector3I.Floor(adjFinalBB.Max); + AABB blockBB; for (int y = bbMin.Y; y <= bbMax.Y; y++) for (int z = bbMin.Z; z <= bbMax.Z; z++) for (int x = bbMin.X; x <= bbMax.X; x++) { BlockID block = game.World.GetPhysicsBlock(x, y, z); - Vector3 min = new Vector3(x, y, z) + BlockInfo.MinBB[block]; - Vector3 max = new Vector3(x, y, z) + BlockInfo.MaxBB[block]; + blockBB.Min = new Vector3(x, y, z) + BlockInfo.MinBB[block]; + blockBB.Max = new Vector3(x, y, z) + BlockInfo.MaxBB[block]; - AABB blockBB = new AABB(min, max); - if (!blockBB.Intersects(adjFinalBB)) - continue; - if (BlockInfo.Collide[block] == CollideType.Solid) - return false; + if (!blockBB.Intersects(adjFinalBB)) continue; + if (BlockInfo.Collide[block] == CollideType.Solid) return false; } return true; } - void ClipX(ref Vector3 size, ref AABB entityBB, ref AABB entityExtentBB) { + void ClipX(ref Vector3 size, ref AABB entityBB, ref AABB extentBB) { entity.Velocity.X = 0; - entityBB.Min.X = entity.Position.X - size.X / 2; entityExtentBB.Min.X = entityBB.Min.X; - entityBB.Max.X = entity.Position.X + size.X / 2; entityExtentBB.Max.X = entityBB.Max.X; + entityBB.Min.X = entity.Position.X - size.X / 2; extentBB.Min.X = entityBB.Min.X; + entityBB.Max.X = entity.Position.X + size.X / 2; extentBB.Max.X = entityBB.Max.X; } - void ClipY(ref Vector3 size, ref AABB entityBB, ref AABB entityExtentBB) { + void ClipY(ref Vector3 size, ref AABB entityBB, ref AABB extentBB) { entity.Velocity.Y = 0; - entityBB.Min.Y = entity.Position.Y; entityExtentBB.Min.Y = entityBB.Min.Y; - entityBB.Max.Y = entity.Position.Y + size.Y; entityExtentBB.Max.Y = entityBB.Max.Y; + entityBB.Min.Y = entity.Position.Y; extentBB.Min.Y = entityBB.Min.Y; + entityBB.Max.Y = entity.Position.Y + size.Y; extentBB.Max.Y = entityBB.Max.Y; } - void ClipZ(ref Vector3 size, ref AABB entityBB, ref AABB entityExtentBB) { + void ClipZ(ref Vector3 size, ref AABB entityBB, ref AABB extentBB) { entity.Velocity.Z = 0; - entityBB.Min.Z = entity.Position.Z - size.Z / 2; entityExtentBB.Min.Z = entityBB.Min.Z; - entityBB.Max.Z = entity.Position.Z + size.Z / 2; entityExtentBB.Max.Z = entityBB.Max.Z; + entityBB.Min.Z = entity.Position.Z - size.Z / 2; extentBB.Min.Z = entityBB.Min.Z; + entityBB.Max.Z = entity.Position.Z + size.Z / 2; extentBB.Max.Z = entityBB.Max.Z; } } } \ No newline at end of file diff --git a/ClassicalSharp/Math/Physics/Searcher.cs b/ClassicalSharp/Math/Physics/Searcher.cs index 8904d4372..d826d65cd 100644 --- a/ClassicalSharp/Math/Physics/Searcher.cs +++ b/ClassicalSharp/Math/Physics/Searcher.cs @@ -7,25 +7,7 @@ using BlockID = System.UInt16; namespace ClassicalSharp.Physics { - public struct State { - public int X, Y, Z; - public float tSquared; - - public State(int x, int y, int z, BlockID block, float tSquared) { - #if !ONLY_8BIT - X = x << 3; Y = y << 4; Z = z << 3; - X |= (block & 0x007); - Y |= (block & 0x078) >> 3; - Z |= (block & 0x380) >> 7; - #else - X = x << 3; Y = y << 3; Z = z << 3; - X |= (block & 0x007); - Y |= (block & 0x038) >> 3; - Z |= (block & 0x1C0) >> 6; - #endif - this.tSquared = tSquared; - } - } + public struct State { public int X, Y, Z; public float tSquared; } /// Calculates all possible blocks that a moving entity can intersect with. public sealed class Searcher { @@ -52,9 +34,10 @@ namespace ClassicalSharp.Physics { int elements = (max.X + 1 - min.X) * (max.Y + 1 - min.Y) * (max.Z + 1 - min.Z); if (elements > stateCache.Length) { stateCache = new State[elements]; - } + } - AABB blockBB = default(AABB); + AABB blockBB; + State state; int count = 0; // Order loops so that we minimise cache misses @@ -72,11 +55,22 @@ namespace ClassicalSharp.Physics { if (!entityExtentBB.Intersects(blockBB)) continue; // necessary for non whole blocks. (slabs) - float tx = 0, ty = 0, tz = 0; + float tx, ty, tz; CalcTime(ref vel, ref entityBB, ref blockBB, out tx, out ty, out tz); if (tx > 1 || ty > 1 || tz > 1) continue; - float tSquared = tx * tx + ty * ty + tz * tz; - stateCache[count++] = new State(x, y, z, block, tSquared); + + #if !ONLY_8BIT + state.X = (x << 3) | (block & 0x007); + state.Y = (y << 4) | ((block & 0x078) >> 3); + state.Z = (z << 3) | ((block & 0x380) >> 7); + #else + state.X = (x << 3) | (block & 0x007); + state.Y = (y << 3) | ((block & 0x038) >> 3); + state.Z = (z << 3) | ((block & 0x1C0) >> 6); + #endif + state.tSquared = tx * tx + ty * ty + tz * tz; + + stateCache[count++] = state; } if (count > 0) diff --git a/src/Client/EntityComponents.c b/src/Client/EntityComponents.c index 796cfaf4a..f9e67cfd0 100644 --- a/src/Client/EntityComponents.c +++ b/src/Client/EntityComponents.c @@ -15,6 +15,10 @@ #include "Physics.h" #include "IModel.h" + +/*########################################################################################################################* +*----------------------------------------------------AnimatedComponent----------------------------------------------------* +*#########################################################################################################################*/ #define ANIM_MAX_ANGLE (110 * MATH_DEG2RAD) #define ANIM_ARM_MAX (60.0f * MATH_DEG2RAD) #define ANIM_LEG_MAX (80.0f * MATH_DEG2RAD) @@ -107,6 +111,9 @@ void AnimatedComp_GetCurrent(AnimatedComp* anim, Real32 t, bool calcHumanAnims) } +/*########################################################################################################################* +*------------------------------------------------------TiltComponent------------------------------------------------------* +*#########################################################################################################################*/ void TiltComp_Init(TiltComp* anim) { anim->TiltX = 0.0f; anim->TiltY = 0.0f; anim->VelTiltStrength = 1.0f; anim->VelTiltStrengthO = 1.0f; anim->VelTiltStrengthN = 1.0f; @@ -133,6 +140,9 @@ void TiltComp_GetCurrent(TiltComp* anim, Real32 t) { } +/*########################################################################################################################* +*-----------------------------------------------------HacksComponent------------------------------------------------------* +*#########################################################################################################################*/ void HacksComp_SetAll(HacksComp* hacks, bool allowed) { hacks->CanAnyHacks = allowed; hacks->CanFly = allowed; hacks->CanNoclip = allowed; hacks->CanRespawn = allowed; @@ -282,6 +292,9 @@ void HacksComp_UpdateState(HacksComp* hacks) { } +/*########################################################################################################################* +*--------------------------------------------------InterpolationComponent-------------------------------------------------* +*#########################################################################################################################*/ void InterpComp_RemoveOldestRotY(InterpComp* interp) { Int32 i; for (i = 0; i < Array_Elems(interp->RotYStates); i++) { @@ -323,6 +336,10 @@ void InterpComp_SetPos(InterpState* state, LocationUpdate* update) { } } + +/*########################################################################################################################* +*----------------------------------------------NetworkInterpolationComponent----------------------------------------------* +*#########################################################################################################################*/ Real32 NetInterpComp_Next(Real32 next, Real32 cur) { if (next == MATH_POS_INF) return cur; return next; @@ -386,6 +403,10 @@ void NetInterpComp_AdvanceState(NetInterpComp* interp) { InterpComp_AdvanceRotY(&interp->Base); } + +/*########################################################################################################################* +*-----------------------------------------------LocalInterpolationComponent-----------------------------------------------* +*#########################################################################################################################*/ Real32 LocalInterpComp_Next(Real32 next, Real32 cur, Real32* last, bool interpolate) { if (next == MATH_POS_INF) return cur; if (!interpolate) *last = next; @@ -440,6 +461,9 @@ void LocalInterpComp_AdvanceState(InterpComp* interp) { } +/*########################################################################################################################* +*-----------------------------------------------------ShadowComponent-----------------------------------------------------* +*#########################################################################################################################*/ Real32 ShadowComponent_radius = 7.0f; typedef struct ShadowData_ { Real32 Y; BlockID Block; UInt8 A; } ShadowData; @@ -638,4 +662,208 @@ void ShadowComponent_Draw(Entity* entity) { UInt32 vCount = (UInt32)(ptr - vertices) / (UInt32)sizeof(VertexP3fT2fC4b); GfxCommon_UpdateDynamicVb_IndexedTris(vb, vertices, vCount); +} + + +typedef struct CollisionsComponent_ { + Entity* Entity; + bool HitXMin, HitYMin, HitZMin, HitXMax, HitYMax, HitZMax, WasOn; +} CollisionsComponent; + +/* Whether a collision occurred with any horizontal sides of any blocks */ +bool Collisions_HitHorizontal(CollisionsComponent* comp) { + return comp->HitXMin || comp->HitXMax || comp->HitZMin || comp->HitZMax; +} + + +/* TODO: test for corner cases, and refactor this */ +void Collisions_MoveAndWallSlide(CollisionsComponent* comp) { + Vector3 zero = Vector3_Zero; + Entity* entity = comp->Entity; + if (Vector3_Equals(&entity->Velocity, &zero)) return; + + AABB entityBB, entityExtentBB; + UInt32 count = Searcher_FindReachableBlocks(entity, &entityBB, &entityExtentBB); + CollideWithReachableBlocks(comp, count, &entityBB, &entityExtentBB); +} + +void Collisions_CollideWithReachableBlocks(CollisionsComponent* comp, UInt32 count, AABB* entityBB, AABB* extentBB) { + Entity* entity = comp->Entity; + /* Reset collision detection states */ + bool wasOn = entity->OnGround; + entity->OnGround = false; + comp->HitXMin = false; comp->HitYMin = false; comp->HitZMin = false; + comp->HitXMax = false; comp->HitYMax = false; comp->HitZMax = false; + + AABB blockBB; + Vector3 bPos, size = entity->Size; + UInt32 i; + for (i = 0; i < count; i++) { + /* Unpack the block and coordinate data */ + SearcherState state = Searcher_States[i]; + bPos.X = state.X >> 3; bPos.Y = state.Y >> 3; bPos.Z = state.Z >> 3; + Int32 block = (state.X & 0x7) | (state.Y & 0x7) << 3 | (state.Z & 0x7) << 6; + + Vector3_Add(&blockBB.Min, &Block_MinBB[block], &bPos); + Vector3_Add(&blockBB.Max, &Block_MaxBB[block], &bPos); + if (!AABB_Intersects(extentBB, &blockBB)) continue; + + /* Recheck time to collide with block (as colliding with blocks modifies this) */ + Real32 tx, ty, tz; + Searcher_CalcTime(&entity->Velocity, entityBB, &blockBB, &tx, &ty, &tz); + if (tx > 1.0f || ty > 1.0f || tz > 1.0f) { + Utils.LogDebug("t > 1 in physics calculation.. this shouldn't have happened."); + } + + /* Calculate the location of the entity when it collides with this block */ + Vector3 v = entity->Velocity; + v.X *= tx; v.Y *= ty; v.Z *= tz; + AABB finalBB; /* Inlined ABBB_Offset */ + Vector3_Add(&finalBB.Min, &entityBB->Min, &v); + Vector3_Add(&finalBB.Min, &entityBB->Max, &v); + + // if we have hit the bottom of a block, we need to change the axis we test first. + if (!hitYMin) { + if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) { + ClipYMax(&blockBB, entityBB, extentBB, size); + } else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) { + ClipYMin(&blockBB, entityBB, extentBB, size); + } else if (finalBB.Min.X + Adjustment >= blockBB.Max.X) { + ClipXMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size); + } else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) { + ClipXMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size); + } else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) { + ClipZMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size); + } else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) { + ClipZMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size); + } + continue; + } + + // if flying or falling, test the horizontal axes first. + if (finalBB.Min.X + Adjustment >= blockBB.Max.X) { + ClipXMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size); + } else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) { + ClipXMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size); + } else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) { + ClipZMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size); + } else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) { + ClipZMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size); + } else if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) { + ClipYMax(&blockBB, entityBB, extentBB, size); + } else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) { + ClipYMin(&blockBB, entityBB, extentBB, size); + } + } +} + +void Collisions_ClipXMin(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) { + if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) { + entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment; + ClipX(size, entityBB, extentBB); + hitXMin = true; + } +} + +void Collisions_ClipXMax(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) { + if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) { + entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment; + ClipX(size, entityBB, extentBB); + hitXMax = true; + } +} + +void Collisions_ClipZMax(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) { + if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) { + entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment; + ClipZ(size, entityBB, extentBB); + hitZMax = true; + } +} + +void Collisions_ClipZMin(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) { + if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) { + entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment; + ClipZ(size, entityBB, extentBB); + hitZMin = true; + } +} + +void Collisions_ClipYMin(AABB* blockBB, AABB* entityBB, AABB* extentBB, Vector3* size) { + entity.Position.Y = blockBB.Min.Y - size.Y - Adjustment; + ClipY(size, entityBB, ref extentBB); + hitYMin = true; +} + +void Collisions_ClipYMax(AABB* blockBB, AABB* entityBB, AABB* extentBB, Vector3* size) { + entity.Position.Y = blockBB.Max.Y + Adjustment; + entity.onGround = true; + ClipY(size, entityBB, ref extentBB); + hitYMax = true; +} + +bool Collisions_DidSlide(AABB blockBB, Vector3* size, AABB* finalBB, AABB* entityBB, AABB* extentBB) { + Real32 yDist = blockBB.Max.Y - entityBB.Min.Y; + if (yDist > 0 && yDist <= entity.StepSize + 0.01f) { + float blockXMin = blockBB.Min.X, blockZMin = blockBB.Min.Z; + blockBB.Min.X = Math.Max(blockBB.Min.X, blockBB.Max.X - size.X / 2); + blockBB.Max.X = Math.Min(blockBB.Max.X, blockXMin + size.X / 2); + blockBB.Min.Z = Math.Max(blockBB.Min.Z, blockBB.Max.Z - size.Z / 2); + blockBB.Max.Z = Math.Min(blockBB.Max.Z, blockZMin + size.Z / 2); + + AABB adjBB; + adjBB.Min.X = min(finalBB->Min.X, blockBB.Min.X + Adjustment); + adjBB.Max.X = max(finalBB->Max.X, blockBB.Max.X - Adjustment); + adjBB.Min.Y = blockBB.Max.Y + Adjustment; + adjBB.Max.Y = adjBB.Min.Y + size->Y; + adjBB.Min.Z = min(finalBB->Min.Z, blockBB.Min.Z + Adjustment); + adjBB.Max.Z = max(finalBB->Max.Z, blockBB.Max.Z - Adjustment); + + if (!Collisions_CanSlideThrough(&adjBB)) return false; + + entity.Position.Y = blockBB.Max.Y + Adjustment; + entity.onGround = true; + ClipY(size, entityBB, extentBB); + return true; + } + return false; +} + +bool Collisions_CanSlideThrough(AABB* adjFinalBB) { + Vector3I bbMin; Vector3I_Floor(&bbMin, &adjFinalBB->Min); + Vector3I bbMax; Vector3I_Floor(&bbMax, &adjFinalBB->Max); + AABB blockBB; + Int32 x, y, z; + + for (y = bbMin.Y; y <= bbMax.Y; y++) { + for (z = bbMin.Z; z <= bbMax.Z; z++) { + for (x = bbMin.X; x <= bbMax.X; x++) { + BlockID block = World_GetPhysicsBlock(x, y, z); + blockBB.Min = new Vector3(x, y, z) + Block_MinBB[block]; + blockBB.Max = new Vector3(x, y, z) + Block_MaxBB[block]; + + if (!AABB_Intersects(&blockBB, adjFinalBB)) continue; + if (Block_Collide[block] == COLLIDE_SOLID) return false; + } + } + } + return true; +} + +void Collisions_ClipX(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) { + entity->Velocity.X = 0.0f; + entityBB->Min.X = entity->Position.X - size->X / 2; extentBB->Min.X = entityBB->Min.X; + entityBB->Max.X = entity->Position.X + size->X / 2; extentBB->Max.X = entityBB->Max.X; +} + +void Collisions_ClipY(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) { + entity->Velocity.Y = 0.0f; + entityBB->Min.Y = entity->Position.Y; extentBB->Min.Y = entityBB->Min.Y; + entityBB->Max.Y = entity->Position.Y + size->Y; extentBB->Max.Y = entityBB->Max.Y; +} + +void Collisions_ClipZ(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) { + entity->Velocity.Z = 0.0f; + entityBB->Min.Z = entity->Position.Z - size->Z / 2; extentBB->Min.Z = entityBB->Min.Z; + entityBB->Max.Z = entity->Position.Z + size->Z / 2; extentBB->Max.Z = entityBB->Max.Z; } \ No newline at end of file diff --git a/src/Client/Physics.c b/src/Client/Physics.c index ccb0f1487..79e40bffd 100644 --- a/src/Client/Physics.c +++ b/src/Client/Physics.c @@ -123,14 +123,6 @@ bool Intersection_RayIntersectsBox(Vector3 origin, Vector3 dir, Vector3 min, Vec } - -void SearcherState_Init(SearcherState* state, Int32 x, Int32 y, Int32 z, BlockID block, Real32 tSquared) { - state->X = (x << 3) | (block & 0x07); - state->Y = (y << 3) | (block & 0x38) >> 3; - state->Z = (z << 3) | (block & 0xC0) >> 6; - state->tSquared = tSquared; -} - #define SEARCHER_STATES_MIN 64 SearcherState Searcher_StatesInitial[SEARCHER_STATES_MIN]; extern SearcherState* Searcher_States = Searcher_StatesInitial; @@ -206,9 +198,11 @@ UInt32 Searcher_FindReachableBlocks(Entity* entity, AABB* entityBB, AABB* entity Real32 tx, ty, tz; Searcher_CalcTime(&vel, entityBB, &blockBB, &tx, &ty, &tz); if (tx > 1.0f || ty > 1.0f || tz > 1.0f) continue; - Real32 tSquared = tx * tx + ty * ty + tz * tz; - SearcherState_Init(curState, x, y, z, block, tSquared); + curState->X = (x << 3) | (block & 0x07); + curState->Y = (y << 3) | ((block & 0x38) >> 3); + curState->Z = (z << 3) | ((block & 0xC0) >> 6); + curState->tSquared = tx * tx + ty * ty + tz * tz; curState++; } }