Skip to content

Commit afe79cb

Browse files
authored
bugfix(dozeraiupdate): Builders now resume their task after having been disabled (TheSuperHackers#1870)
1 parent 831b810 commit afe79cb

9 files changed

Lines changed: 188 additions & 12 deletions

File tree

Generals/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class DozerAIInterface
140140
// task actions
141141
virtual void newTask( DozerTask task, Object *target ) = 0; ///< set a desire to do the requrested task
142142
virtual void cancelTask( DozerTask task ) = 0; ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
143+
virtual void resumePreviousTask(void) = 0; ///< resume the previous task if there was one
143144

144145
// internal methods to manage behavior from within the dozer state machine
145146
virtual void internalTaskComplete( DozerTask task ) = 0; ///< set a dozer task as successfully completed
@@ -239,6 +240,7 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface
239240
// task actions
240241
virtual void newTask( DozerTask task, Object *target ); ///< set a desire to do the requrested task
241242
virtual void cancelTask( DozerTask task ); ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
243+
virtual void resumePreviousTask(void); ///< resume the previous task if there was one
242244

243245
// internal methods to manage behavior from within the dozer state machine
244246
virtual void internalTaskComplete( DozerTask task ); ///< set a dozer task as successfully completed
@@ -276,12 +278,20 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface
276278

277279
struct DozerTaskInfo
278280
{
281+
DozerTaskInfo()
282+
{
283+
m_targetObjectID = INVALID_ID;
284+
m_taskOrderFrame = 0;
285+
}
286+
279287
ObjectID m_targetObjectID; ///< target object ID of task
280288
UnsignedInt m_taskOrderFrame; ///< logic frame we decided we wanted to do this task
281289
} m_task[ DOZER_NUM_TASKS ]; ///< tasks we want to do indexed by DozerTask
282290

283291
DozerPrimaryStateMachine *m_dozerMachine; ///< the custom state machine for Dozer behavior
284292
DozerTask m_currentTask; ///< current task the dozer is attending to (if any)
293+
DozerTask m_previousTask; ///< previous task the dozer was attending to (if any)
294+
DozerTaskInfo m_previousTaskInfo; ///< info on the previous task the dozer was attending to (if any)
285295
AudioEventRTS m_buildingSound; ///< sound is pulled from the object we are building!
286296
Bool m_isRebuild; ///< is this a rebuild of a previous building?
287297

Generals/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class WorkerAIUpdate : public AIUpdateInterface, public DozerAIInterface, public
155155
// task actions
156156
virtual void newTask( DozerTask task, Object* target ); ///< set a desire to do the requrested task
157157
virtual void cancelTask( DozerTask task ); ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
158+
virtual void resumePreviousTask(void); ///< resume the previous task if there was one
158159

159160
// internal methods to manage behavior from within the dozer state machine
160161
virtual void internalTaskComplete( DozerTask task ); ///< set a dozer task as successfully completed
@@ -212,12 +213,20 @@ class WorkerAIUpdate : public AIUpdateInterface, public DozerAIInterface, public
212213
// Dozer data
213214
struct DozerTaskInfo
214215
{
216+
DozerTaskInfo()
217+
{
218+
m_targetObjectID = INVALID_ID;
219+
m_taskOrderFrame = 0;
220+
}
221+
215222
ObjectID m_targetObjectID; ///< target object ID of task
216223
UnsignedInt m_taskOrderFrame; ///< logic frame we decided we wanted to do this task
217224
} m_task[ DOZER_NUM_TASKS ]; ///< tasks we want to do indexed by DozerTask
218225

219226

220227
DozerTask m_currentTask; ///< current task the dozer is attending to (if any)
228+
DozerTask m_previousTask; ///< previous task the dozer was attending to (if any)
229+
DozerTaskInfo m_previousTaskInfo; ///< info on the previous task the dozer was attending to (if any)
221230

222231
//
223232
// the following info array can be used if we want to have more complicated approaches

Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,7 @@ DozerAIUpdate::DozerAIUpdate( Thing *thing, const ModuleData* moduleData ) :
14521452

14531453
}
14541454
m_currentTask = DOZER_TASK_INVALID;
1455+
m_previousTask = DOZER_TASK_INVALID;
14551456

14561457
m_buildSubTask = DOZER_SELECT_BUILD_DOCK_LOCATION; // irrelavant, but I want non-garbage value
14571458

@@ -2040,6 +2041,19 @@ void DozerAIUpdate::cancelTask( DozerTask task )
20402041

20412042
}
20422043

2044+
//-------------------------------------------------------------------------------------------------
2045+
/** Attempt to resume the previous task */
2046+
//-------------------------------------------------------------------------------------------------
2047+
void DozerAIUpdate::resumePreviousTask(void)
2048+
{
2049+
if (m_previousTask != DOZER_TASK_INVALID)
2050+
{
2051+
newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID));
2052+
m_previousTask = DOZER_TASK_INVALID;
2053+
m_previousTaskInfo = DozerTaskInfo();
2054+
}
2055+
}
2056+
20432057
//-------------------------------------------------------------------------------------------------
20442058
/** Is there a given task waiting to be done */
20452059
//-------------------------------------------------------------------------------------------------
@@ -2096,6 +2110,9 @@ void DozerAIUpdate::internalTaskComplete( DozerTask task )
20962110
m_task[ task ].m_targetObjectID = INVALID_ID;
20972111
m_task[ task ].m_taskOrderFrame = 0;
20982112

2113+
m_previousTask = DOZER_TASK_INVALID;
2114+
m_previousTaskInfo = DozerTaskInfo();
2115+
20992116
// remove dock point info for this task
21002117
for( Int i = 0; i < DOZER_NUM_DOCK_POINTS; i++ )
21012118
m_dockPoint[ task ][ i ].valid = FALSE;
@@ -2118,6 +2135,9 @@ void DozerAIUpdate::internalCancelTask( DozerTask task )
21182135
// call the single method that gets called for completing and canceling tasks
21192136
internalTaskCompleteOrCancelled( task );
21202137

2138+
m_previousTask = task;
2139+
m_previousTaskInfo = m_task[task];
2140+
21212141
// remove the info for this task
21222142
m_task[ task ].m_targetObjectID = INVALID_ID;
21232143
m_task[ task ].m_taskOrderFrame = 0;
@@ -2436,12 +2456,18 @@ void DozerAIUpdate::crc( Xfer *xfer )
24362456
// ------------------------------------------------------------------------------------------------
24372457
/** Xfer method
24382458
* Version Info:
2439-
* 1: Initial version */
2459+
* 1: Initial version
2460+
* 2: TheSuperHackers @tweak Stubbjax 17/11/2025 Save the dozer's previous task
2461+
*/
24402462
// ------------------------------------------------------------------------------------------------
24412463
void DozerAIUpdate::xfer( Xfer *xfer )
24422464
{
24432465
// version
2444-
XferVersion currentVersion = 1;
2466+
#if RETAIL_COMPATIBLE_XFER_SAVE
2467+
XferVersion currentVersion = 1;
2468+
#else
2469+
XferVersion currentVersion = 2;
2470+
#endif
24452471
XferVersion version = currentVersion;
24462472
xfer->xferVersion( &version, currentVersion );
24472473

@@ -2462,6 +2488,12 @@ void DozerAIUpdate::xfer( Xfer *xfer )
24622488
xfer->xferSnapshot(m_dozerMachine);
24632489
xfer->xferUser(&m_currentTask, sizeof(m_currentTask));
24642490

2491+
if (currentVersion >= 2)
2492+
{
2493+
xfer->xferUser(&m_previousTask, sizeof(m_previousTask));
2494+
xfer->xferUser(&m_previousTaskInfo, sizeof(m_previousTaskInfo));
2495+
}
2496+
24652497
Int dockPoints = DOZER_NUM_DOCK_POINTS;
24662498
xfer->xferInt(&dockPoints);
24672499
if (dockPoints!=DOZER_NUM_DOCK_POINTS) {

Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ WorkerAIUpdate::WorkerAIUpdate( Thing *thing, const ModuleData* moduleData ) :
100100
}
101101
}
102102
m_currentTask = DOZER_TASK_INVALID;
103+
m_previousTask = DOZER_TASK_INVALID;
103104
m_buildSubTask = DOZER_SELECT_BUILD_DOCK_LOCATION; // irrelavant, but I want non-garbage value
104105

105106
m_supplyTruckStateMachine = nullptr;
@@ -695,6 +696,19 @@ void WorkerAIUpdate::cancelTask( DozerTask task )
695696

696697
}
697698

699+
//-------------------------------------------------------------------------------------------------
700+
/** Attempt to resume the previous task */
701+
//-------------------------------------------------------------------------------------------------
702+
void WorkerAIUpdate::resumePreviousTask(void)
703+
{
704+
if (m_previousTask != DOZER_TASK_INVALID)
705+
{
706+
newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID));
707+
m_previousTask = DOZER_TASK_INVALID;
708+
m_previousTaskInfo = DozerTaskInfo();
709+
}
710+
}
711+
698712
//-------------------------------------------------------------------------------------------------
699713
/** Is there a given task waiting to be done */
700714
//-------------------------------------------------------------------------------------------------
@@ -751,6 +765,9 @@ void WorkerAIUpdate::internalTaskComplete( DozerTask task )
751765
m_task[ task ].m_targetObjectID = INVALID_ID;
752766
m_task[ task ].m_taskOrderFrame = 0;
753767

768+
m_previousTask = DOZER_TASK_INVALID;
769+
m_previousTaskInfo = DozerTaskInfo();
770+
754771
// remove dock point info for this task
755772
for( Int i = 0; i < DOZER_NUM_DOCK_POINTS; i++ )
756773
m_dockPoint[ task ][ i ].valid = FALSE;
@@ -773,6 +790,9 @@ void WorkerAIUpdate::internalCancelTask( DozerTask task )
773790
// call the single method that gets called for completing and canceling tasks
774791
internalTaskCompleteOrCancelled( task );
775792

793+
m_previousTask = task;
794+
m_previousTaskInfo = m_task[task];
795+
776796
// remove the info for this task
777797
m_task[ task ].m_targetObjectID = INVALID_ID;
778798
m_task[ task ].m_taskOrderFrame = 0;
@@ -1401,11 +1421,17 @@ void WorkerAIUpdate::crc( Xfer *xfer )
14011421
// ------------------------------------------------------------------------------------------------
14021422
/** Xfer method
14031423
* Version Info:
1404-
* 1: Initial version */
1424+
* 1: Initial version
1425+
* 2: TheSuperHackers @tweak Stubbjax 17/11/2025 Save the worker's previous task
1426+
*/
14051427
// ------------------------------------------------------------------------------------------------
14061428
void WorkerAIUpdate::xfer( Xfer *xfer )
14071429
{
1408-
XferVersion currentVersion = 1;
1430+
#if RETAIL_COMPATIBLE_XFER_SAVE
1431+
XferVersion currentVersion = 1;
1432+
#else
1433+
XferVersion currentVersion = 2;
1434+
#endif
14091435
XferVersion version = currentVersion;
14101436
xfer->xferVersion( &version, currentVersion );
14111437

@@ -1429,6 +1455,12 @@ void WorkerAIUpdate::xfer( Xfer *xfer )
14291455
xfer->xferSnapshot(m_dozerMachine);
14301456
xfer->xferUser(&m_currentTask, sizeof(m_currentTask));
14311457

1458+
if (currentVersion >= 2)
1459+
{
1460+
xfer->xferUser(&m_previousTask, sizeof(m_previousTask));
1461+
xfer->xferUser(&m_previousTaskInfo, sizeof(m_previousTaskInfo));
1462+
}
1463+
14321464
Int dockPoints = DOZER_NUM_DOCK_POINTS;
14331465
xfer->xferInt(&dockPoints);
14341466
if (dockPoints!=DOZER_NUM_DOCK_POINTS) {

GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class DozerAIInterface
140140
// task actions
141141
virtual void newTask( DozerTask task, Object *target ) = 0; ///< set a desire to do the requested task
142142
virtual void cancelTask( DozerTask task ) = 0; ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
143+
virtual void resumePreviousTask(void) = 0; ///< resume the previous task if there was one
143144

144145
// internal methods to manage behavior from within the dozer state machine
145146
virtual void internalTaskComplete( DozerTask task ) = 0; ///< set a dozer task as successfully completed
@@ -239,6 +240,7 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface
239240
// task actions
240241
virtual void newTask( DozerTask task, Object *target ); ///< set a desire to do the requested task
241242
virtual void cancelTask( DozerTask task ); ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
243+
virtual void resumePreviousTask(void); ///< resume the previous task if there was one
242244

243245
// internal methods to manage behavior from within the dozer state machine
244246
virtual void internalTaskComplete( DozerTask task ); ///< set a dozer task as successfully completed
@@ -276,12 +278,20 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface
276278

277279
struct DozerTaskInfo
278280
{
281+
DozerTaskInfo()
282+
{
283+
m_targetObjectID = INVALID_ID;
284+
m_taskOrderFrame = 0;
285+
}
286+
279287
ObjectID m_targetObjectID; ///< target object ID of task
280288
UnsignedInt m_taskOrderFrame; ///< logic frame we decided we wanted to do this task
281289
} m_task[ DOZER_NUM_TASKS ]; ///< tasks we want to do indexed by DozerTask
282290

283291
DozerPrimaryStateMachine *m_dozerMachine; ///< the custom state machine for Dozer behavior
284292
DozerTask m_currentTask; ///< current task the dozer is attending to (if any)
293+
DozerTask m_previousTask; ///< previous task the dozer was attending to (if any)
294+
DozerTaskInfo m_previousTaskInfo; ///< info on the previous task the dozer was attending to (if any)
285295
AudioEventRTS m_buildingSound; ///< sound is pulled from the object we are building!
286296
Bool m_isRebuild; ///< is this a rebuild of a previous building?
287297

GeneralsMD/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class WorkerAIUpdate : public AIUpdateInterface, public DozerAIInterface, public
158158
// task actions
159159
virtual void newTask( DozerTask task, Object* target ); ///< set a desire to do the requested task
160160
virtual void cancelTask( DozerTask task ); ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
161+
virtual void resumePreviousTask(void); ///< resume the previous task if there was one
161162

162163
// internal methods to manage behavior from within the dozer state machine
163164
virtual void internalTaskComplete( DozerTask task ); ///< set a dozer task as successfully completed
@@ -217,12 +218,20 @@ class WorkerAIUpdate : public AIUpdateInterface, public DozerAIInterface, public
217218
// Dozer data
218219
struct DozerTaskInfo
219220
{
221+
DozerTaskInfo()
222+
{
223+
m_targetObjectID = INVALID_ID;
224+
m_taskOrderFrame = 0;
225+
}
226+
220227
ObjectID m_targetObjectID; ///< target object ID of task
221228
UnsignedInt m_taskOrderFrame; ///< logic frame we decided we wanted to do this task
222229
} m_task[ DOZER_NUM_TASKS ]; ///< tasks we want to do indexed by DozerTask
223230

224231

225232
DozerTask m_currentTask; ///< current task the dozer is attending to (if any)
233+
DozerTask m_previousTask; ///< previous task the dozer was attending to (if any)
234+
DozerTaskInfo m_previousTaskInfo; ///< info on the previous task the dozer was attending to (if any)
226235

227236
//
228237
// the following info array can be used if we want to have more complicated approaches

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3853,11 +3853,21 @@ void Object::onDisabledEdge(Bool becomingDisabled)
38533853
(*module)->onDisabledEdge( becomingDisabled );
38543854

38553855
DozerAIInterface *dozerAI = getAI() ? getAI()->getDozerAIInterface() : nullptr;
3856-
if( becomingDisabled && dozerAI )
3856+
if (dozerAI)
38573857
{
3858-
// Have to say goodbye to the thing we might be building or repairing so someone else can do it.
3859-
if( dozerAI->getCurrentTask() != DOZER_TASK_INVALID )
3860-
dozerAI->cancelTask( dozerAI->getCurrentTask() );
3858+
if (becomingDisabled)
3859+
{
3860+
// Have to say goodbye to the thing we might be building or repairing so someone else can do it.
3861+
if (dozerAI->getCurrentTask() != DOZER_TASK_INVALID)
3862+
dozerAI->cancelTask(dozerAI->getCurrentTask());
3863+
}
3864+
else
3865+
{
3866+
#if !RETAIL_COMPATIBLE_CRC
3867+
// TheSuperHackers @bugfix Stubbjax 17/11/2025 Resume previous task when re-enabled.
3868+
dozerAI->resumePreviousTask();
3869+
#endif
3870+
}
38613871
}
38623872

38633873
Player* controller = getControllingPlayer();

0 commit comments

Comments
 (0)