Merge pull request from Wargus/tim/desync-debugging

desync debugging
This commit is contained in:
Tim Felgentreff 2022-02-20 14:52:03 +01:00 committed by GitHub
commit e75958d2ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 249 additions and 79 deletions

10
.vscode/launch.json vendored
View file

@ -14,7 +14,7 @@
"windows": {
"type": "cppvsdbg",
"program": "${workspaceFolder}/build/Debug/stratagus-dbg.exe",
"args": ["-W", "-p", "-a", "-d", "${workspaceFolder}\\..\\data.${input:game}"],
"args": ["-W", "-i", "-p", "-P", "${input:port}", "-a", "-d", "${workspaceFolder}\\..\\data.${input:game}"],
"environment": [
{"name": "PATH", "value": "${workspaceFolder}\\..\\dependencies\\bin;${env:PATH}"},
{"name": "OMP_WAIT_POLICY", "value": "passive"}
@ -23,7 +23,7 @@
},
"stopAtEntry": false,
"cwd": "${workspaceFolder}/../${input:game}",
}
},
],
"inputs": [
{
@ -37,5 +37,11 @@
],
"default": "wargus"
},
{
"type": "promptString",
"id": "port",
"description": "Network port?",
"default": "6600"
}
]
}

View file

@ -221,6 +221,8 @@ COrder_Resource::~COrder_Resource()
worker->DeAssignWorkerFromMine(*mine);
}
Depot = NULL;
CUnit *goal = this->GetGoal();
if (goal) {
// If mining decrease the active count on the resource.
@ -908,10 +910,19 @@ int COrder_Resource::StopGathering(CUnit &unit)
// Find and send to resource deposit.
CUnit *depot = FindDeposit(unit, 1000, unit.CurrentResource);
// There's a bug in the traversal that leads to workers "sometimes" not finding their way to the old depot.
// timfel: of course, maybe it's actually nice that workers drop out towards their last depot...
if (!depot && (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) && Depot && Depot->IsAlive()) {
CUnit *depot = FindDeposit(unit, 1000, unit.CurrentResource);
Assert(unit.Container);
DropOutNearest(unit, Depot->tilePos + Depot->Type->GetHalfTileSize(), source);
}
Depot = depot;
if (!depot || !unit.ResourcesHeld || this->Finished) {
if (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) {
Assert(unit.Container);
DropOutOnSide(unit, LookingW, source);
if (unit.Container) {
DropOutOnSide(unit, LookingW, source);
}
}
CUnit *mine = this->Resource.Mine;
@ -921,13 +932,15 @@ int COrder_Resource::StopGathering(CUnit &unit)
}
DebugPrint("%d: Worker %d report: Can't find a resource [%d] deposit.\n"
_C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.CurrentResource);
_C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.CurrentResource);
this->Finished = true;
return 0;
} else {
if (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) {
Assert(unit.Container);
DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(), source);
if (unit.Container) {
// may have dropped out above
DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(), source);
}
}
UnitGotoGoal(unit, depot, SUB_MOVE_TO_DEPOT);
}

View file

@ -77,6 +77,14 @@
#include "unit_manager.h"
#include "unittype.h"
#ifdef USE_STACKTRACE
#include <stdexcept>
#include <stacktrace/call_stack.hpp>
#include <stacktrace/stack_exception.hpp>
#else
#include "st_backtrace.h"
#endif
/*----------------------------------------------------------------------------
-- Variables
----------------------------------------------------------------------------*/
@ -483,11 +491,38 @@ static void DumpUnitInfo(CUnit &unit)
}
fprintf(logf, "%lu: ", GameCycle);
fprintf(logf, "%d %s %d P%d Refs %d: %X %d,%d %d,%d\n",
const char *currentAction;
switch (!unit.Orders.empty() ? unit.CurrentAction() : -1) {
case -1: currentAction = "No Orders"; break;
case UnitActionNone: currentAction = "None"; break;
case UnitActionStill: currentAction = "Still"; break;
case UnitActionStandGround: currentAction = "StandGround"; break;
case UnitActionFollow: currentAction = "Follow"; break;
case UnitActionDefend: currentAction = "Defend"; break;
case UnitActionMove: currentAction = "Move"; break;
case UnitActionAttack: currentAction = "Attack"; break;
case UnitActionAttackGround: currentAction = "AttackGround"; break;
case UnitActionDie: currentAction = "Die"; break;
case UnitActionSpellCast: currentAction = "SpellCast"; break;
case UnitActionTrain: currentAction = "Train"; break;
case UnitActionUpgradeTo: currentAction = "UpgradeTo"; break;
case UnitActionResearch: currentAction = "Research"; break;
case UnitActionBuilt: currentAction = "Built"; break;
case UnitActionBoard: currentAction = "Board"; break;
case UnitActionUnload: currentAction = "Unload"; break;
case UnitActionPatrol: currentAction = "Patrol"; break;
case UnitActionBuild: currentAction = "Build"; break;
case UnitActionExplore: currentAction = "Explore"; break;
case UnitActionRepair: currentAction = "Repair"; break;
case UnitActionResource: currentAction = "Resource"; break;
case UnitActionTransformInto: currentAction = "TransformInto"; break;
}
fprintf(logf, "%d %s %s P%d Refs %d: Seed %X Hash %X %d@%d %d@%d\n",
UnitNumber(unit), unit.Type ? unit.Type->Ident.c_str() : "unit-killed",
!unit.Orders.empty() ? unit.CurrentAction() : -1,
unit.Player ? unit.Player->Index : -1, unit.Refs, SyncRandSeed,
unit.tilePos.x, unit.tilePos.y, unit.IX, unit.IY);
currentAction, unit.Player ? unit.Player->Index : -1, unit.Refs,
SyncRandSeed, SyncHash, unit.tilePos.x, unit.tilePos.y, unit.IX, unit.IY);
#if 0
SaveUnit(unit, logf);
#endif
@ -532,10 +567,18 @@ static void UnitActionsEachCycle(UNITP_ITERATOR begin, UNITP_ITERATOR end)
if (EnableUnitDebug) {
DumpUnitInfo(unit);
}
// Calculate some hash.
SyncHash = (SyncHash << 5) | (SyncHash >> 27);
SyncHash ^= unit.Orders.empty() == false ? unit.CurrentAction() << 18 : 0;
SyncHash ^= unit.Refs << 3;
if (EnableUnitDebug) {
fprintf(stderr, "GameCycle: %lud, new SyncHash: %x (unit: %d:%s, order: %d, refs: %d)\n", GameCycle, SyncHash,
UnitNumber(unit), unit.Type->Ident.c_str(), unit.Orders.empty() ? -1 : unit.CurrentAction(), unit.Refs);
print_backtrace(8);
fflush(stderr);
}
}
}

View file

@ -926,7 +926,7 @@ void AiCanNotMove(CUnit &unit)
const int gh = unit.pathFinderData->input.GetGoalSize().y;
AiPlayer = unit.Player->Ai;
if (PlaceReachable(unit, goalPos, gw, gh, 0, 255)) {
if (PlaceReachable(unit, goalPos, gw, gh, 0, 255, false)) {
// Path probably closed by unit here
AiMoveUnitInTheWay(unit);
}

View file

@ -219,13 +219,13 @@ extern void FreePathfinder();
/// Returns the next element of the path
extern int NextPathElement(CUnit &unit, short int *xdp, short int *ydp);
/// Return path length to unit 'dst'.
extern int UnitReachable(const CUnit &src, const CUnit &dst, int range);
extern int UnitReachable(const CUnit &src, const CUnit &dst, int range, bool from_outside_container);
/// Return path length to unit 'dst' or error code.
extern int CalcPathLengthToUnit(const CUnit &src, const CUnit &dst,
const int minrange, const int range);
/// Can the unit 'src' reach the place x,y
extern int PlaceReachable(const CUnit &src, const Vec2i &pos, int w, int h,
int minrange, int maxrange);
int minrange, int maxrange, bool from_outside_container);
//
// in astar.cpp

View file

@ -16,13 +16,12 @@ inline void print_backtrace(int sz = 100) {
#elif defined(USE_WIN32)
#if 1 // the below would mean we give up XP support
#include "windows.h"
#include "winbase.h"
#include "dbghelp.h"
#include "process.h"
inline void print_backtrace(void) {
inline void print_backtrace(int sz = 100) {
unsigned int i;
void *stack[100];
unsigned short frames;
@ -34,7 +33,7 @@ inline void print_backtrace(void) {
process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
frames = CaptureStackBackTrace(0, 100, stack, NULL);
frames = CaptureStackBackTrace(0, sz, stack, NULL);
fprintf(stderr, "backtrace returned %d addresses\n", frames);
symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
symbol->MaxNameLen = 1024;
@ -58,17 +57,12 @@ inline void print_backtrace(void) {
}
free(symbol);
}
#else
inline void print_backtrace(void) {
}
#endif
#else
inline void print_backtrace(void) {
inline void print_backtrace(int sz = 100) {
}
#endif
#endif

View file

@ -227,6 +227,9 @@ public:
unsigned char getCost() const { return cost; }
unsigned int getFlag() const { return Flags; }
void setGraphicTile(unsigned int tile) { this->tile = tile; }
#ifdef DEBUG
int64_t lastAStarCost; /// debugging pathfinder
#endif
private:
#ifdef DEBUG
unsigned int tilesetTile; /// tileset tile number

View file

@ -286,6 +286,38 @@ void CViewport::DrawMapBackgroundInViewport() const
tile = mf.playerInfo.SeenTile;
}
Map.TileGraphic->DrawFrameClip(tile, dx, dy);
#if 0
int64_t cost = mf.lastAStarCost;
int32_t alpha;
// we use the msb as marker, but only consider the lower 32-bits as numeric value
if (cost != 0) {
if (cost == -1) {
// non traversible tiles always start full red
alpha = -60;
} else if (cost > 0) {
// msb not set means this has not been scaled
// scale cost to be between 1 and 60
cost <<= 3;
if (cost > 60) {
cost = 60;
}
alpha = static_cast<int32_t>(cost);
} else {
// consider only low 32-bits of already scaled value
alpha = static_cast<int32_t>(cost);
}
}
if (alpha > 0) {
Video.FillTransRectangleClip(ColorGreen, dx, dy,
dx + Map.TileGraphic->getWidth(), dy + dx + Map.TileGraphic->getWidth(), alpha * 200 / 60);
alpha--;
} else if (alpha < 0) {
Video.FillTransRectangleClip(ColorRed, dx, dy,
dx + Map.TileGraphic->getWidth(), dy + dx + Map.TileGraphic->getWidth(), -alpha * 200 / 60);
alpha++;
}
const_cast<CMapField &>(mf).lastAStarCost = alpha | ((uint64_t)1 << 63);
#endif
++sx;
dx += PixelTileSize.x;
}

View file

@ -51,6 +51,13 @@
#include "video.h"
#include "../video/intern_video.h"
#ifdef USE_STACKTRACE
#include <stdexcept>
#include <stacktrace/call_stack.hpp>
#include <stacktrace/stack_exception.hpp>
#else
#include "st_backtrace.h"
#endif
/*----------------------------------------------------------------------------
-- Variables
@ -205,6 +212,7 @@ void MapMarkTileSight(const CPlayer &player, const unsigned int index)
{
CMapField &mf = *Map.Field(index);
unsigned short *v = &(mf.playerInfo.Visible[player.Index]);
if (*v == 0 || *v == 1) { // Unexplored or unseen
// When there is no fog only unexplored tiles are marked.
if (!Map.NoFogOfWar || *v == 0) {
@ -214,10 +222,25 @@ void MapMarkTileSight(const CPlayer &player, const unsigned int index)
if (mf.playerInfo.IsTeamVisible(*ThisPlayer)) {
Map.MarkSeenTile(mf);
}
return;
} else {
Assert(*v != 65535);
++*v;
}
Assert(*v != 65535);
++*v;
#if 0
if (EnableDebugPrint) {
fprintf(stderr, "Mapsight: GameCycle: %lud, SyncHash before: %x", GameCycle, SyncHash);
}
// Calculate some hash.
SyncHash = (SyncHash << 5) | (SyncHash >> 27);
SyncHash ^= (*v << 16) | *v;
if (EnableDebugPrint) {
fprintf(stderr, ", after: %x (mapfield: %d, player: %d, sight: %d)\n", SyncHash,
index, player.Index, *v);
print_backtrace(8);
fflush(stderr);
}
#endif
}
void MapMarkTileSight(const CPlayer &player, const Vec2i &pos)

View file

@ -250,6 +250,8 @@
// Declaration
//----------------------------------------------------------------------------
extern int SaveGame(const std::string &filename); /// Save game
/**
** Network command input/output queue.
*/
@ -298,8 +300,8 @@ CUDPSocket NetworkFildes; /// Network file descriptor
static unsigned long NetworkLastFrame[PlayerMax]; /// Last frame received packet
static unsigned long NetworkLastCycle[PlayerMax]; /// Last cycle received packet
static int NetworkSyncSeeds[256]; /// Network sync seeds.
static int NetworkSyncHashs[256]; /// Network sync hashs.
static unsigned int NetworkSyncSeeds[256]; /// Network sync seeds.
static unsigned int NetworkSyncHashs[256]; /// Network sync hashs.
static CNetworkCommandQueue NetworkIn[256][PlayerMax][MaxNetworkCommands]; /// Per-player network packet input queue
static std::deque<CNetworkCommandQueue> CommandsIn; /// Network command input queue
static std::deque<CNetworkCommandQueue> MsgCommandsIn; /// Network message input queue
@ -917,8 +919,8 @@ static void NetworkExecCommand_Sync(const CNetworkCommandQueue &ncq)
CNetworkCommandSync nc;
nc.Deserialize(&ncq.Data[0]);
const unsigned long gameNetCycle = GameCycle;
const int syncSeed = nc.syncSeed;
const int syncHash = nc.syncHash;
const unsigned int syncSeed = nc.syncSeed;
const unsigned int syncHash = nc.syncHash;
if (syncSeed != NetworkSyncSeeds[gameNetCycle & 0xFF]
|| syncHash != NetworkSyncHashs[gameNetCycle & 0xFF]) {
@ -929,10 +931,20 @@ static void NetworkExecCommand_Sync(const CNetworkCommandQueue &ncq)
// only print this message circa every 5 seconds...
SetMessage("%s", _("Network out of sync"));
gameInSync = false;
SetGamePaused(true);
time_t now;
time(&now);
std::string savefile = "desync_savegame_";
savefile += std::to_string(ThisPlayer->Index);
savefile += "_";
savefile += std::to_string((intmax_t)now);
savefile += ".sav";
SaveGame(savefile);
}
DebugPrint("\nNetwork out of sync %x!=%x! %d!=%d! Cycle %lu\n\n" _C_
DebugPrint("\nNetwork out of sync seed: %X!=%X , hash: %X!=%X Cycle %lu\n\n" _C_
syncSeed _C_ NetworkSyncSeeds[gameNetCycle & 0xFF] _C_
syncHash _C_ NetworkSyncHashs[gameNetCycle & 0xFF] _C_ GameCycle);
syncHash _C_ NetworkSyncHashs[gameNetCycle & 0xFF] _C_ GameCycle);
} else {
gameInSync = true;
}

View file

@ -534,12 +534,18 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit)
if (flag && (AStarKnowUnseenTerrain || mf->playerInfo.IsExplored(*unit.Player))) {
if (flag & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit)) {
// we can't cross fixed units and other unpassable things
#ifdef DEBUG
const_cast<CMapField *>(mf)->lastAStarCost = -1;
#endif
return -1;
}
CUnit *goal = mf->UnitCache.find(unit_finder);
if (!goal) {
// Shouldn't happen, mask says there is something on this tile
Assert(0);
#ifdef DEBUG
const_cast<CMapField *>(mf)->lastAStarCost = -1;
#endif
return -1;
}
if (goal->Moving) {
@ -549,6 +555,9 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit)
// for non moving unit Always Fail unless goal is unit, or unit can attack the target
if (&unit != goal) {
if (GetAStarFixedEnemyUnitsUnpassable() == true) {
#ifdef DEBUG
const_cast<CMapField *>(mf)->lastAStarCost = -1;
#endif
return -1;
}
if (goal->Player->IsEnemy(unit) && unit.IsAgressive() && CanTarget(*unit.Type, *goal->Type)
@ -556,6 +565,9 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit)
cost += 2 * AStarMovingUnitCrossingCost;
} else {
// FIXME: Need support for moving a fixed unit to add cost
#ifdef DEBUG
const_cast<CMapField *>(mf)->lastAStarCost = -1;
#endif
return -1;
}
//cost += AStarFixedUnitCrossingCost;
@ -569,6 +581,9 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit)
}
// Add tile movement cost
cost += mf->getCost();
#ifdef DEBUG
const_cast<CMapField *>(mf)->lastAStarCost = cost;
#endif
++mf;
} while (--i);
index += AStarMapWidth;

View file

@ -183,33 +183,68 @@ void FreePathfinder()
**
** @return Distance to place.
*/
int PlaceReachable(const CUnit &src, const Vec2i &goalPos, int w, int h, int minrange, int range)
int PlaceReachable(const CUnit &src, const Vec2i &goalPos, int w, int h, int minrange, int range, bool from_outside_container)
{
SetAStarFixedEnemyUnitsUnpassable(true); /// change Path Finder setting to don't count tiles with enemy units as passable
int i = AStarFindPath(src.tilePos, goalPos, w, h,
src.Type->TileWidth, src.Type->TileHeight,
minrange, range, NULL, 0, src);
int i;
Vec2i srcTilePos = src.tilePos;
int srcTW = src.Type->TileWidth;
int srcTH = src.Type->TileHeight;
if (!from_outside_container || !src.Container) {
i = AStarFindPath(srcTilePos, goalPos, w, h,
srcTW, srcTH,
minrange, range, nullptr, 0, src);
} else {
const CUnit *first_container = GetFirstContainer(src);
const Vec2i offset(1, 1);
int containerW = first_container->Type->TileWidth;
int containerH = first_container->Type->TileHeight;
Vec2i containerTilePos = first_container->tilePos;
// check top and bottom rows and left and right columns around the container
for (int x = -1; x <= containerW; x++) {
for (int y = -1; y <= containerH; y++) {
if (x >= 0 && x < containerW && y >= 0 && y < containerH) {
// inside the container, no need to check
continue;
}
Vec2i tile_pos = containerTilePos + Vec2i(x, y);
if (!Map.Info.IsPointOnMap(tile_pos)) {
continue;
}
if (!CanMoveToMask(tile_pos, src.Type->MovementMask)) {
//ignore tiles to which the unit cannot be dropped from its container
continue;
}
i = AStarFindPath(tile_pos, goalPos, w, h,
srcTW, srcTH,
minrange, range, nullptr, 0, src);
switch (i) {
case PF_FAILED:
case PF_UNREACHABLE:
case PF_WAIT:
continue;
}
goto finished;
}
}
}
finished:
SetAStarFixedEnemyUnitsUnpassable(false); /// restore Path Finder setting
switch (i) {
case PF_FAILED:
case PF_UNREACHABLE:
i = 0;
break;
case PF_WAIT:
return 0;
case PF_REACHED:
/* since most of this function usage check return value as bool
* then reached state should be track as true value */
i = 1;
break;
case PF_WAIT:
Assert(0);
i = 0;
break;
case PF_MOVE:
break;
* then reached state should be track as true value */
return std::max(i, 1);
default:
break;
return i;
}
return i;
}
/**
@ -221,14 +256,14 @@ int PlaceReachable(const CUnit &src, const Vec2i &goalPos, int w, int h, int min
**
** @return Distance to place.
*/
int UnitReachable(const CUnit &src, const CUnit &dst, int range)
int UnitReachable(const CUnit &src, const CUnit &dst, int range, bool from_outside_container)
{
// Find a path to the goal.
if (src.Type->Building) {
return 0;
}
const int depth = PlaceReachable(src, dst.tilePos,
dst.Type->TileWidth, dst.Type->TileHeight, 0, range);
dst.Type->TileWidth, dst.Type->TileHeight, 0, range, from_outside_container);
if (depth <= 0) {
return 0;
}

View file

@ -87,7 +87,7 @@ int SyncRand()
if (EnableDebugPrint) {
fprintf(stderr, "GameCycle: %lud, seed: %x, Sync rand: %d\n", GameCycle, SyncRandSeed, val);
print_backtrace();
print_backtrace(8);
fflush(stderr);
}
return val;

View file

@ -430,43 +430,45 @@ void CUnit::Init()
pathFinderData = new PathFinderData;
pathFinderData->input.SetUnit(*this);
Frame = 0;
Colors = -1;
memset(IndividualUpgrades, 0, sizeof(IndividualUpgrades));
IX = 0;
IY = 0;
Frame = 0;
Direction = 0;
CurrentResource = 0;
ResourcesHeld = 0;
DamagedType = ANIMATIONS_DEATHTYPES;
Attacked = 0;
Summoned = 0;
Blink = 0;
Moving = 0;
ReCast = 0;
AutoRepair = 0;
Burning = 0;
Destroyed = 0;
Removed = 0;
Selected = 0;
TeamSelected = 0;
Constructed = 0;
Active = 0;
Boarded = 0;
CacheLock = 0;
Waiting = 0;
MineLow = 0;
TeamSelected = 0;
RescuedFrom = NULL;
memset(VisCount, 0, sizeof(VisCount));
memset(&Seen, 0, sizeof(Seen));
delete Variable;
Variable = NULL;
TTL = 0;
Threshold = 0;
UnderAttack = 0;
GroupId = 0;
LastGroup = 0;
ResourcesHeld = 0;
Wait = 0;
Blink = 0;
Moving = 0;
ReCast = 0;
CacheLock = 0;
Summoned = 0;
Waiting = 0;
MineLow = 0;
Threshold = 0;
UnderAttack = 0;
memset(&Anim, 0, sizeof(Anim));
memset(&WaitBackup, 0, sizeof(WaitBackup));
CurrentResource = 0;
Orders.clear();
delete SavedOrder;
SavedOrder = NULL;
@ -478,9 +480,7 @@ void CUnit::Init()
AutoCastSpell = NULL;
delete SpellCoolDownTimers;
SpellCoolDownTimers = NULL;
AutoRepair = 0;
Goal = NULL;
memset(IndividualUpgrades, 0, sizeof(IndividualUpgrades));
}
CUnit::~CUnit() {
@ -2984,7 +2984,7 @@ static void HitUnit_AttackBack(CUnit &attacker, CUnit &target)
COrder_Attack &order = dynamic_cast<COrder_Attack &>(*target.CurrentOrder());
if (order.IsAutoTargeting() || target.Player->AiEnabled) {
if (attacker.IsVisibleAsGoal(*target.Player)) {
if (UnitReachable(target, attacker, target.Stats->Variables[ATTACKRANGE_INDEX].Max)) {
if (UnitReachable(target, attacker, target.Stats->Variables[ATTACKRANGE_INDEX].Max, false)) {
target.UnderAttack = underAttack; /// allow target to ignore non aggressive targets while searching attacker
order.OfferNewTarget(target, &attacker);
}
@ -3018,7 +3018,7 @@ static void HitUnit_AttackBack(CUnit &attacker, CUnit &target)
const Vec2i posToAttack = (attacker.IsVisibleAsGoal(*target.Player))
? attacker.tilePos
: GetRndPosInDirection(target.tilePos, attacker.tilePos, false, target.Type->ReactRangeComputer, 2);
if (!PlaceReachable(target, posToAttack, 1, 1, 0, target.Stats->Variables[ATTACKRANGE_INDEX].Max)) {
if (!PlaceReachable(target, posToAttack, 1, 1, 0, target.Stats->Variables[ATTACKRANGE_INDEX].Max, false)) {
return;
}
COrder *savedOrder = NULL;

View file

@ -213,14 +213,8 @@ class BestDepotFinder
return;
}
// calck real travel distance
if (worker->Container != nullptr) {
UnmarkUnitFieldFlags(*first_container);
}
const int travel_distance = UnitReachable(*worker, *dest, 1);
if (worker->Container != nullptr) {
MarkUnitFieldFlags(*first_container);
}
// calc real travel distance
const int travel_distance = UnitReachable(*worker, *dest, 1, worker->Container != nullptr);
//
// Take this depot?
//
@ -730,7 +724,7 @@ private:
// Unit in range ?
const int d = attacker->MapDistanceTo(*dest);
if (d > attackrange && !UnitReachable(*attacker, *dest, attackrange)) {
if (d > attackrange && !UnitReachable(*attacker, *dest, attackrange, false)) {
return INT_MAX;
}
@ -934,7 +928,7 @@ public:
int attackrange = attacker->Stats->Variables[ATTACKRANGE_INDEX].Max;
if (d <= attackrange ||
(d <= range && UnitReachable(*attacker, *dest, attackrange))) {
(d <= range && UnitReachable(*attacker, *dest, attackrange, false))) {
++enemy_count;
} else {
dest->CacheLock = 1;