diff --git a/src/Client/Entity.c b/src/Client/Entity.c index f4fbab618..d2deaf4e0 100644 --- a/src/Client/Entity.c +++ b/src/Client/Entity.c @@ -33,7 +33,7 @@ void LocationUpdate_Construct(LocationUpdate* update, Real32 x, Real32 y, Real32 update->RelativePosition = relPos; } -#define exc LOCATIONUPDATE_EXCLUDED +#define exc MATH_POS_INF void LocationUpdate_Empty(LocationUpdate* update) { LocationUpdate_Construct(update, 0.0f, 0.0f, 0.0f, exc, exc, exc, exc, false, false); } @@ -348,7 +348,7 @@ void Entities_Remove(EntityID id) { EntityID Entities_GetCloset(Entity* src) { Vector3 eyePos = Entity_GetEyePosition(src); Vector3 dir = Vector3_GetDirVector(src->HeadY * MATH_DEG2RAD, src->HeadX * MATH_DEG2RAD); - Real32 closestDist = float.PositiveInfinity; + Real32 closestDist = MATH_POS_INF; EntityID targetId = ENTITIES_SELF_ID; UInt32 i; diff --git a/src/Client/Entity.h b/src/Client/Entity.h index 7ac073af2..1e653ca84 100644 --- a/src/Client/Entity.h +++ b/src/Client/Entity.h @@ -15,8 +15,6 @@ typedef struct IModel_ IModel; /* Forward declaration */ /* Offset used to avoid floating point roundoff errors. */ #define ENTITY_ADJUSTMENT 0.001f -/* Special value specifying an angle is not included in an orientation update. */ -#define LOCATIONUPDATE_EXCLUDED -100000.31415926535f /* Maxmimum number of characters in a model name. */ #define ENTITY_MAX_MODEL_LENGTH 10 @@ -46,7 +44,7 @@ typedef bool (*TouchesAny_Condition)(BlockID block); typedef struct LocationUpdate_ { /* Position of the update (if included). */ Vector3 Pos; - /* Orientation of the update (if included). If not, has the value of LOCATIONUPDATE_EXCLUDED. */ + /* Orientation of the update (if included). If not, has the value of MATH_POS_INF. */ Real32 RotX, RotY, RotZ, HeadX; bool IncludesPosition, RelativePosition; } LocationUpdate; diff --git a/src/Client/EntityComponents.c b/src/Client/EntityComponents.c index 91bb9441f..0dcd921ee 100644 --- a/src/Client/EntityComponents.c +++ b/src/Client/EntityComponents.c @@ -154,7 +154,7 @@ void HacksComp_Init(HacksComp* hacks) { hacks->MaxJumps = 1; hacks->NoclipSlide = true; hacks->CanBePushed = true; - hacks->HacksFlags = String_InitAndClear(&hacks->HacksFlagsBuffer[0], 128); + hacks->HacksFlags = String_InitAndClearArray(hacks->HacksFlagsBuffer); } bool HacksComp_CanJumpHigher(HacksComp* hacks) { @@ -326,7 +326,7 @@ void InterpComp_SetPos(InterpState* state, LocationUpdate* update) { } Real32 NetInterpComp_Next(Real32 next, Real32 cur) { - if (next == LOCATIONUPDATE_EXCLUDED) return cur; + if (next == MATH_POS_INF) return cur; return next; } @@ -389,7 +389,7 @@ void NetInterpComp_AdvanceState(NetInterpComp* interp) { } Real32 LocalInterpComp_Next(Real32 next, Real32 cur, Real32* last, bool interpolate) { - if (next == LOCATIONUPDATE_EXCLUDED) return cur; + if (next == MATH_POS_INF) return cur; if (!interpolate) *last = next; return next; } @@ -416,7 +416,7 @@ void LocalInterpComp_SetLocation(InterpComp* interp, LocationUpdate* update, boo next->HeadX = LocalInterpComp_Next(update->HeadX, next->HeadX, &prev->HeadX, interpolate); next->HeadY = LocalInterpComp_Next(update->RotY, next->HeadY, &prev->HeadY, interpolate); - if (update->RotY != LOCATIONUPDATE_EXCLUDED) { + if (update->RotY != MATH_POS_INF) { if (!interpolate) { interp->NextRotY = update->RotY; entity->RotY = update->RotY; diff --git a/src/Client/ExtMath.h b/src/Client/ExtMath.h index 4fb41d1ab..654a416ac 100644 --- a/src/Client/ExtMath.h +++ b/src/Client/ExtMath.h @@ -10,6 +10,7 @@ #define MATH_DEG2RAD (MATH_PI / 180.0f) #define MATH_RAD2DEG (180.0f / MATH_PI) #define MATH_LARGENUM 1000000000.0f +#define MATH_POS_INF ((Real32)(1e+300 * 1e+300)) #define Math_Deg2Packed(x) ((UInt8)((x) * 256.0f / 360.0f)) #define Math_Packed2Deg(x) ((x) * 360.0f / 256.0f) diff --git a/src/Client/Searcher.c b/src/Client/Searcher.c new file mode 100644 index 000000000..6df4b4585 --- /dev/null +++ b/src/Client/Searcher.c @@ -0,0 +1,121 @@ +#include "Searcher.h" +#include "Block.h" +#include "World.h" +#include "Platform.h" +#include "ExtMath.h" +#include "Funcs.h" + +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; +UInt32 Searcher_StatesCount = SEARCHER_STATES_MIN; + +void Searcher_QuickSort(Int32 left, Int32 right) { + SearcherState* keys = Searcher_States; SearcherState key; + while (left < right) { + Int32 i = left, j = right; + Real32 pivot = keys[(i + j) >> 1].tSquared; + + /* partition the list */ + while (i <= j) { + while (pivot > keys[i].tSquared) i++; + while (pivot < keys[j].tSquared) j--; + QuickSort_Swap_Maybe(); + } + /* recurse into the smaller subset */ + QuickSort_Recurse(Searcher_QuickSort); + } +} + +UInt32 Searcher_FindReachableBlocks(Entity* entity, AABB* entityBB, AABB* entityExtentBB) { + Vector3 vel = entity->Velocity; + Entity_GetBounds(entity, entityBB); + + /* Exact maximum extent the entity can reach, and the equivalent map coordinates. */ + entityExtentBB->Min.X = entityBB->Min.X + (vel.X < 0.0f ? vel.X : 0.0f); + entityExtentBB->Min.Y = entityBB->Min.Y + (vel.Y < 0.0f ? vel.Y : 0.0f); + entityExtentBB->Min.Z = entityBB->Min.Z + (vel.Z < 0.0f ? vel.Z : 0.0f); + + entityExtentBB->Max.X = entityBB->Max.X + (vel.X > 0.0f ? vel.X : 0.0f); + entityExtentBB->Max.Y = entityBB->Max.Y + (vel.Y > 0.0f ? vel.Y : 0.0f); + entityExtentBB->Max.Z = entityBB->Max.Z + (vel.Z > 0.0f ? vel.Z : 0.0f); + + Vector3I min, max; + Vector3I_Floor(&min, &entityExtentBB->Min); + Vector3I_Floor(&max, &entityExtentBB->Max); + + UInt32 elements = (max.X - min.X + 1) * (max.Y - min.Y + 1) * (max.Z - min.Z + 1); + if (elements > Searcher_StatesCount) { + if (Searcher_StatesCount > SEARCHER_STATES_MIN) { + Platform_MemFree(Searcher_States); + } + Searcher_StatesCount = elements; + + Searcher_States = Platform_MemAlloc(elements * sizeof(SearcherState)); + if (Searcher_States == NULL) { + ErrorHandler_Fail("Failed to allocate memory for Searcher_FindReachableBlocks"); + } + } + + /* Order loops so that we minimise cache misses */ + AABB blockBB; + UInt32 count = 0; + Int32 x, y, z; + SearcherState* curState = Searcher_States; + + for (y = min.Y; y <= max.Y; y++) { + for (z = min.Z; z <= max.Z; z++) { + for (x = min.X; x <= max.X; x++) { + BlockID block = World_GetPhysicsBlock(x, y, z); + if (Block_Collide[block] != COLLIDE_SOLID) continue; + Real32 xx = (Real32)x, yy = (Real32)y, zz = (Real32)z; + + blockBB.Min = Block_MinBB[block]; + blockBB.Min.X += xx; blockBB.Min.Y += yy; blockBB.Min.Z += zz; + blockBB.Max = Block_MaxBB[block]; + blockBB.Max.X += xx; blockBB.Max.Y += yy; blockBB.Max.Z += zz; + + if (!AABB_Intersects(entityExtentBB, &blockBB)) continue; /* necessary for non whole blocks. (slabs) */ + + 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++; + } + } + } + + if (count > 0) Searcher_QuickSort(0, count - 1); + return count; +} + + +void Searcher_CalcTime(Vector3* vel, AABB *entityBB, AABB* blockBB, Real32* tx, Real32* ty, Real32* tz) { + Real32 dx = vel->X > 0.0f ? blockBB->Min.X - entityBB->Max.X : entityBB->Min.X - blockBB->Max.X; + Real32 dy = vel->Y > 0.0f ? blockBB->Min.Y - entityBB->Max.Y : entityBB->Min.Y - blockBB->Max.Y; + Real32 dz = vel->Z > 0.0f ? blockBB->Min.Z - entityBB->Max.Z : entityBB->Min.Z - blockBB->Max.Z; + + *tx = vel->X == 0.0f ? MATH_POS_INF : Math_AbsF(dx / vel->X); + *ty = vel->Y == 0.0f ? MATH_POS_INF : Math_AbsF(dy / vel->Y); + *tz = vel->Z == 0.0f ? MATH_POS_INF : Math_AbsF(dz / vel->Z); + + if (entityBB->Max.X >= blockBB->Min.X && entityBB->Min.X <= blockBB->Max.X) *tx = 0.0f; /* Inlined XIntersects */ + if (entityBB->Max.Y >= blockBB->Min.Y && entityBB->Min.Y <= blockBB->Max.Y) *ty = 0.0f; /* Inlined YIntersects */ + if (entityBB->Max.Z >= blockBB->Min.Z && entityBB->Min.Z <= blockBB->Max.Z) *tz = 0.0f; /* Inlined ZIntersects */ +} + +void Searcher_Free(void) { + if (Searcher_StatesCount > SEARCHER_STATES_MIN) { + Platform_MemFree(Searcher_States); + } +} \ No newline at end of file diff --git a/src/Client/Searcher.h b/src/Client/Searcher.h new file mode 100644 index 000000000..8a2d5ce2f --- /dev/null +++ b/src/Client/Searcher.h @@ -0,0 +1,16 @@ +#include "Typedefs.h" +#include "Entity.h" + +/* Calculates all possible blocks that a moving entity can intersect with. + Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 +*/ + +typedef struct SearcherState_ { + Int32 X, Y, Z; + Real32 tSquared; +} SearcherState; +extern SearcherState* Searcher_States; + +UInt32 Searcher_FindReachableBlocks(Entity* entity, AABB* entityBB, AABB* entityExtentBB); +void Searcher_CalcTime(Vector3* vel, AABB *entityBB, AABB* blockBB, Real32* tx, Real32* ty, Real32* tz); +void Searcher_Free(void); \ No newline at end of file