Skip to content

Commit

Permalink
A* intermediate Phobos-developers#1
Browse files Browse the repository at this point in the history
  • Loading branch information
Multfinite committed Mar 26, 2024
1 parent 59b383b commit fe3afaa
Show file tree
Hide file tree
Showing 6 changed files with 654 additions and 5 deletions.
202 changes: 197 additions & 5 deletions src/Reimplementation/AStar/AStar.Bugfixes.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,214 @@
#include <AStarClass.h>
#include <Utilities/Macro.h>
#include <Utilities/Debug.h>

#include <HouseClass.h>
#include <FootClass.h>
#include <MapClass.h>
#include <CellClass.h>

constexpr size_t SubzoneTrackingStructSize = sizeof(DynamicVectorClass<SubzoneTrackingStruct>);

#pragma optimize( "", off )
DEFINE_NAKED_HOOK(0x42C4FE, AStar_FindPathHierarchical_Patch)
/*
CellLevelPassabilityStruct.SubzoneIndex (uint16)
0x582019
*/

/*
LevelAndPassabilityStruct2.SubzoneIndex (uint16)
0x582019
*/

/*
LevelAndPassabilityStruct2.SubzoneIndex_byPathEnum (uint16[3])
0x58200F
*/

/*
DEFINE_HOOK(0x42C34A, AStar__FindPathHierarchical_42C34A, 5)
{
GET_STACK(CellClass*, from, 0x70);
GET_STACK(CellClass*, to, 0x74);
GET(int, stage, ESI);
auto* map = MapClass::Instance.get();
int fromLinearIndex = map->GetCellIndex_Safe((const CoordStruct&) from->Position);
int toLinearIndex = map->GetCellIndex_Safe((const CoordStruct&) to->Position);
auto& fromStruct = map->arrLevelAndPassability2[fromLinearIndex];
auto& toStruct = map->arrLevelAndPassability2[toLinearIndex];
Debug::Log("(0x42C34A) Subzone indexes (stage: %d):\nfrom (%d, %d) = %d [%d, %d, %d]\nto (%d, %d) = %d [%d, %d, %d]\n"
, stage
, from->Position.X, from->Position.Y, fromLinearIndex, fromStruct.SubzoneIndex_byPathEnum[0], fromStruct.SubzoneIndex_byPathEnum[1], fromStruct.SubzoneIndex_byPathEnum[2]
, to->Position.X, to->Position.Y, toLinearIndex, toStruct.SubzoneIndex_byPathEnum[0], toStruct.SubzoneIndex_byPathEnum[1], toStruct.SubzoneIndex_byPathEnum[2]
);
int fromSubzoneIndex = fromStruct.SubzoneIndex_byPathEnum[stage];
int toSubzoneIndex = toStruct.SubzoneIndex_byPathEnum[stage];
R->EBX(fromSubzoneIndex);
R->Stack<int>(0x34, fromSubzoneIndex);
R->Stack<int>(0x3C, toSubzoneIndex);
return 0x42C377;
}
*/

DEFINE_HOOK(0x42C4FE, AStar__FindPathHierarchical_42C4FE, 5)
{
GET(int, subzoneIndex, ECX);
GET(int, pathenum, ESI);

auto* map = MapClass::Instance.get();

auto& subzones = map->SubzoneTracking[pathenum];

if (subzoneIndex < 0 || subzoneIndex >= subzones.Count)
{
Debug::LogAndMessage("(0x42C4FE) Subzone index: %d (0x%X) must be in range [0; %d)]\n",
subzoneIndex, subzoneIndex, subzones.Count
);

R->EAX(-1);
R->ECX(0);
R->EDX(0);
return 0x42C740;
}

auto& subzone = subzones.Items[subzoneIndex];
auto& connections = subzone.SubzoneConnections;

R->EAX(subzoneIndex);
R->ECX(connections.Count);
R->EDX(connections.Items);
return connections.Count > 0 ? 0x42C519 : 0x42C740;
}

inline void ResetTracking(MapClass* pThis, int cellIndex, HierarchicalStage stage, int x, int y)
{
auto& cellInfo = pThis->SubzonesLinking[cellIndex];

auto& subzonesThis = pThis->SubzoneTracking[stage];
auto& subzonesNext = pThis->SubzoneTracking[stage + 1];

int subzoneIndexThis = cellInfo.SubzoneHierarchy[stage];
int subzoneIndexNext = cellInfo.SubzoneHierarchy[stage + 1];
if (subzoneIndexThis >= 0 && subzoneIndexThis < subzonesNext.Count)
{
subzonesNext.Items[subzoneIndexThis].SubzoneIndex = subzoneIndexNext;
/*
Debug::Log("(0x584D5C) Subzone index: %d, stage: %d, indexes: [%d, %d, %d]\n",
subzoneIndexThis
, x, y
, stage
, cellInfo.SubzoneIndex_byPathEnum[0], cellInfo.SubzoneIndex_byPathEnum[1], cellInfo.SubzoneIndex_byPathEnum[2]
);
*/
}
else
{
Debug::LogAndMessage("(0x584D5C) Subzone index: %d (0x%X) must be in range [0; %d)] at cell (%d, %d), stage: %d, indexes: [%d, %d, %d]\n",
subzoneIndexThis, subzoneIndexThis, subzonesNext.Count
, x, y
, stage
, cellInfo.SubzoneHierarchy[0], cellInfo.SubzoneHierarchy[1], cellInfo.SubzoneHierarchy[2]
);
}
}

DEFINE_HOOK(0x584D5C, MapClass__SubzoneZoneReset_584D5C, 5)
{
GET(MapClass*, pThis, EBX);
GET(int, x, ESI);
GET(int, y, EDI);

auto cellIndex = pThis->GetCellIndex_Safe(x, y);

// see 0x567110
if (cellIndex >= 0 && cellIndex < pThis->ValidMapCellCount)
{
ResetTracking(pThis, cellIndex, HierarchicalStage::STAGE_0, x, y);
ResetTracking(pThis, cellIndex, HierarchicalStage::STAGE_1, x, y);
}
else
{
Debug::LogAndMessage("(0x584D5C) Cell index is incorrect: %d (0x%X) at (%d, %d), ValidMapCellCount is %d\n",
cellIndex, cellIndex
, x, y
, pThis->ValidMapCellCount
);
}
return 0x584DFE;
}

/*
DEFINE_HOOK(0x584DD6, MapClass__SubzoneZoneReset_584DD6, 5)
{
GET(int, cellIndex, EAX);
GET(MapClass*, pThis, EBX);
GET(int, x, ESI);
GET(int, y, EDI);
// see 0x567110
if (cellIndex >= 0 && cellIndex < pThis->ValidMapCellCount)
{
ResetTracking(pThis, cellIndex, PathEnum::PATH_0, x, y);
ResetTracking(pThis, cellIndex, PathEnum::PATH_1, x, y);
}
else
{
Debug::LogAndMessage("(0x584DD6) Cell index is incorrect: %d (0x%X) at (%d, %d), ValidMapCellCount is %d\n",
cellIndex, cellIndex
, x, y
, pThis->ValidMapCellCount
);
}
return 0x584DFE;
}
*/

/*
DEFINE_HOOK(0x42C47B, AStar__FindPathHierarchical_42C47B, 7)
{
GET(int, fromSubzoneIndex, EBX);
GET(AStarClass*, pThis, EDI);
GET(int, pathenum, ESI);
GET_STACK(int*, ints_4C_costs, 0x24);
GET_STACK(float*, hierarchicalCosts, 0x28);
GET_STACK(CellClass*, from, 0x70);
auto* map = MapClass::Instance.get();
auto& subzones = map->SubzoneTracking[pathenum];
if (fromSubzoneIndex >= 0 && fromSubzoneIndex < subzones.Count)
{
ints_4C_costs[fromSubzoneIndex] = pThis->initedcount;
hierarchicalCosts[fromSubzoneIndex] = 0.0f;
}
else
{
Debug::LogAndMessage("(0x42C47B) Subzone index: %d (0x%X) must be in range [0; %d)] at cell (%d, %d)\n",
fromSubzoneIndex, fromSubzoneIndex, subzones.Count
, from->Position.X, from->Position.Y
);
}
return 0x42C494;
}
*/

/*
DEFINE_NAKED_HOOK(0x42C4FE, AStar__FindPathHierarchical_Patch)
{
__asm
{
lea eax, [ecx + ecx * 8]
cmp eax, 0
jl loc_0x42C740 // index is negative (subzoneIndex < 0)
mov ecx, [edx + (0x87F874 + 0x10)]
cmp eax, ecx
cmp eax, ecx
jge loc_0x42C740 // index out of range of vector (subzoneIndex >= vector.Count)
mov ecx, [edx + (0x87F874 + 0x4)]
mov edx, [ecx + eax * 4 + 4]
Expand All @@ -39,7 +231,7 @@ DEFINE_NAKED_HOOK(0x42C4FE, AStar_FindPathHierarchical_Patch)
}
}
DEFINE_NAKED_HOOK(0x584DE4, MapClass_subzone_Zone_Reset_584550_Patched)
DEFINE_NAKED_HOOK(0x584DE4, MapClass__subzone_Zone_Reset_584550_Patch)
{
__asm
{
Expand Down Expand Up @@ -72,4 +264,4 @@ DEFINE_NAKED_HOOK(0x584DE4, MapClass_subzone_Zone_Reset_584550_Patched)
jmp edi
}
}
#pragma optimize( "", on )
*/
47 changes: 47 additions & 0 deletions src/Reimplementation/AStar/AStar.FindPath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "AStar.hpp"
#include <MapClass.h>
#include <FootClass.h>
#include <InfantryClass.h>
#include <LocomotionClass.h>

PathType* AStar::FindPath(
CellStruct* from, CellStruct* to
, FootClass* object
, FacingType* way, int maxLoop, MovementZone movementZoneOverride
, HierarchicalStage stage)
{
auto* map = MapClass::Instance.get();
auto* technoType = object->GetTechnoType();

boolpathfind_38 = true;
Cleanup();
for (auto& v : CellIndexesVector)
v.Clear();

__Blockage = stage;
CellClass* fromCell = map->GetCellAt(*from);
CellClass* toCell = map->GetCellAt(*to);

auto movementZoneOfObject = movementZoneOverride == MovementZone::None ? technoType->MovementZone : movementZoneOverride;

auto fromZoneType = map->GetMovementZoneType(*from, movementZoneOfObject, object->OnBridge);
auto toZoneType = map->GetMovementZoneType(*to, movementZoneOfObject, toCell->ContainsBridge());

auto src = map->SubzoneBridgeCheck_583180(fromCell, object->OnBridge);
auto dst = map->SubzoneBridgeCheck_583180(toCell, toCell->ContainsBridge());

if (object->AbsID == AbstractType::Infantry && technoType->JumpJet)
{
auto* inf = (InfantryClass*) object;
movementZoneOfObject = MovementZone::Infantry;

void* ppvObject;
ILocomotion* locomotor = object->Locomotor;
auto status = locomotor ? locomotor->QueryInterface(__uuidof(IPersist), &ppvObject) : E_POINTER;
if (status < 0)
_com_issue_error(status);

}


}
109 changes: 109 additions & 0 deletions src/Reimplementation/AStar/AStar.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#pragma once
#include <AStarClass.h>

class NOVTABLE __declspec(align(4)) AStar
{
public:
static constexpr reference<AStar, 0x87E8B8> const Instance {};

char bool_0;
bool ScaleMovementCost;
char bool_2;
char __DoPostProcess;
float MovementCostScaler;
char CheckLocomotor;
AStarWorkPathStructDataHeap* WorkingNodesBuffer;
AStarWorkPathStructHeap* WorkingNodes;
PriorityQueueClass<AStarWorkPathStruct>* OpenNodes;
int* celllevel_costarray2_alt;
int* celllevel_costarray1;
float* MovementCosts;
float* MovementCostsAlt;
DWORD initedcount;
DWORD ObjectSpeed;
int CurrentCellLevel;
int DestCellLevel;
bool boolpathfind_38;
HierarchicalStage __Blockage;
int* ints_40_costs[3];
int* ints_4C_costs[3];
float* HierarchicalCosts[3];
AStarQueueNodeHierarchical* HierarchicalOpenNodesBuffer;
PriorityQueueClass<AStarQueueNodeHierarchical>* HierarchicalOpenNodes;
int CellsProcessed;
CellStruct CurrentCell;
DynamicVectorClass<DWORD> CellIndexesVector[3];
unsigned __int16 somearray_BC[1500];
int counts_for_subzones_field_C74[3];

double GetMovementCost(
CellClass** from, CellClass** to
, bool useAlt, MoveType move
, FootClass* object
)
{
JMP_THIS(0x429830);
}
PathType* FindPathRegular(
CellStruct* from, CellStruct* to
, FootClass* object, FacingType* moves
, signed int maxLoops, HierarchicalStage postProcess
)
{
JMP_THIS(0x429A90);
}
AStarWorkPathStruct* CreateNode(
AStarWorkPathStructNode** pathNodes
, CellClass** a3, CellStruct* a4
, float movementCost
)
{
JMP_THIS(0x42A460);
}
void Cleanup() { JMP_THIS(0x42A5B0); }
bool IsSameCostCommon(int a2, char a3, int a4) { JMP_THIS(0x42A690); }
AStar() { JMP_THIS(0x42A6D0); }
~AStar() { JMP_THIS(0x42A900); }
PathType* BuildFinalPathRegular(AStarWorkPathStruct* workPath, FacingType* moves)
{ JMP_THIS(0x42AA90); }
void ReinitCostArrays(RectangleStruct* where) { JMP_THIS(0x42AC00); }
char PostProcessCells(FootClass* object) { JMP_THIS(0x42ACF0); }
FootClass* GetOccupierRegular(CellStruct* pos, int level) { JMP_THIS(0x42B080); };
void ProcessFinalPathRegular(PathType* path, FootClass* object) { JMP_THIS(0x42B210); }
int FixupFinalPathRegular(int a2, CellStruct a3, int a4, int a5, int a6, int a7)
{ JMP_THIS(0x42B420); }
void OptimizeFinalPath(PathType* path, FootClass* object) { JMP_THIS(0x42B7F0); }
void AdjacentCellRegular(FacingType* moves, int a3, int a4, int a5, CellStruct* cellOut)
{ JMP_THIS(0x42BCA0); }
bool PlotStraightLineRegular(
FacingType* moves, int arg4
, CellStruct* a4, CellStruct* a5
, FootClass* object, int* overlap, int a8)
{
JMP_THIS(0x42BE20);
};
DWORD* ClearPointers() { JMP_THIS(0x42C1C0); }
bool FindPathHierarchical(
CellStruct* from, CellStruct* to
, MovementZone movementZone, FootClass* object)
{
JMP_THIS(0x42C290);
}
PathType* FindPath(
CellStruct* from, CellStruct* to
, FootClass* object
, FacingType* way, int maxLoop, MovementZone movementZoneOverride
, HierarchicalStage stage);

void InitCellIndexSets(int a2) { JMP_THIS(0x42CCD0); }
bool IsCellIndexSetRegistered(int xPos, int yPos, int vectorNum) { JMP_THIS(0x42CEB0); }
void RegisterCellIndexSet(unsigned int xPos, unsigned int yPos, int vectorNum)
{ JMP_THIS(0x42CF10); }
void RegisterCellIndexSets(SubzoneTrackingStruct* tracking, HierarchicalStage postProcess)
{ JMP_THIS(0x42CF80); }
unsigned int TestCellWalk(CellStruct* a2, CellStruct* a3, FootClass* object, bool bridge1, int bridge2, MovementZone zoneType)
{ JMP_THIS(0x42D170); }
};

constexpr size_t AStarSize = sizeof(AStar);
static_assert(AStarSize == 0xC80, "AStar size must be C80h (3200d)!");
Loading

0 comments on commit fe3afaa

Please sign in to comment.