Fix respawn/spawn timers racing ahead under multi-threading
POSIX clock() sums CPU time across every thread in the process, unlike Windows' clock() which tracks wall-clock milliseconds. With several worker threads running, respawn/spawn/AI timers based on clock() raced far ahead of real elapsed time. Switch spawn-timer bookkeeping to time(NULL)/time_t (seconds) throughout the world server, and add a portable clock() shim in sockets.h (backed by CLOCK_MONOTONIC, millisecond resolution) for remaining call sites so CLOCKS_PER_SEC==1000 still holds like it did on Windows. Also: fix MapDelay/VisualDelay/WorldDelay being passed to usleep() (us) without converting from their configured milliseconds; fix the shutdown timer likewise; stop leaking the temporary actor used to run an NPC's AIP script; fix CleanDrops() skipping the element that shifts into position after an erase. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1f626c6b93
commit
725620e23c
8 files changed
+66
-37
No files matched your search
@@ -306,11 +306,13 @@ void CMap::UpdateTime( )
|
||||
// Clean Drops
|
||||
void CMap::CleanDrops( )
|
||||
{
|
||||
for(UINT j=0;j<DropsList.size();j++)
|
||||
for(UINT j=0;j<DropsList.size();)
|
||||
{
|
||||
CDrop* thisdrop = DropsList.at(j);
|
||||
if( time(NULL) - thisdrop->droptime >= 50 )
|
||||
DeleteDrop( thisdrop );
|
||||
DeleteDrop( thisdrop ); // erases this element, so don't advance j - the next drop just shifted into position j
|
||||
else
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,19 +326,19 @@ void CMap::RespawnMonster( )
|
||||
CSpawnArea* thisspawn = MonsterSpawnList.at(k);
|
||||
|
||||
if (thisspawn->respawntime<2)thisspawn->respawntime=2;
|
||||
clock_t rtime = clock() - thisspawn->lastRespawnTime;
|
||||
if((rtime > thisspawn->respawntime*CLOCKS_PER_SEC && thisspawn->amon<thisspawn->max)|| thisspawn->amon<thisspawn->min )
|
||||
time_t rtime = time(NULL) - thisspawn->lastRespawnTime;
|
||||
if((rtime > thisspawn->respawntime && thisspawn->amon<thisspawn->max)|| thisspawn->amon<thisspawn->min )
|
||||
{
|
||||
fPoint position = GServer->RandInPoly( thisspawn->points, thisspawn->pcount );
|
||||
AddMonster( thisspawn->montype, position, 0, thisspawn->mobdrop, thisspawn->mapdrop, thisspawn->id );
|
||||
thisspawn->lastRespawnTime = clock();
|
||||
thisspawn->lastRespawnTime = time(NULL);
|
||||
}
|
||||
}*/
|
||||
//PY new spawn code
|
||||
for(UINT k=0;k<MonsterSpawnList.size( );k++)
|
||||
{
|
||||
CSpawnArea* thisspawn = MonsterSpawnList.at(k);
|
||||
clock_t rtime = clock() - thisspawn->lastRespawnTime;
|
||||
time_t rtime = time(NULL) - thisspawn->lastRespawnTime;
|
||||
if(thisspawn->limit == 1 && IsNight()) //spawn limit is set to day only
|
||||
continue;
|
||||
if(thisspawn->RefVar != 0 && thisspawn->RefVal != 0) //only allow this spawn if the correct ObjVar is set to non zero
|
||||
@@ -352,18 +354,18 @@ void CMap::RespawnMonster( )
|
||||
// no spawn. this spawn area is inactive
|
||||
break;
|
||||
case 1: //normal spawn
|
||||
if(rtime > (thisspawn->respawntime * CLOCKS_PER_SEC) && thisspawn->amon < thisspawn->max)
|
||||
if(rtime > (thisspawn->respawntime) && thisspawn->amon < thisspawn->max)
|
||||
{
|
||||
fPoint position = GServer->RandInCircle( thisspawn->point, thisspawn->radius );
|
||||
UINT aggro = thisspawn->aggressive;
|
||||
AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit );
|
||||
thisspawn->lastRespawnTime = clock();
|
||||
thisspawn->lastRespawnTime = time(NULL);
|
||||
UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters
|
||||
thisspawn->triggercount = 0;
|
||||
}
|
||||
break;
|
||||
case 2: //normal but fill the spawn
|
||||
if(rtime > (thisspawn->respawntime * CLOCKS_PER_SEC) && thisspawn->amon < thisspawn->max)
|
||||
if(rtime > (thisspawn->respawntime) && thisspawn->amon < thisspawn->max)
|
||||
{
|
||||
for(int i=1;i<thisspawn->max;i++)
|
||||
{
|
||||
@@ -372,6 +374,7 @@ void CMap::RespawnMonster( )
|
||||
AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit );
|
||||
UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters
|
||||
}
|
||||
thisspawn->lastRespawnTime = time(NULL);
|
||||
}
|
||||
break;
|
||||
case 3: //cascade spawn
|
||||
@@ -380,7 +383,7 @@ void CMap::RespawnMonster( )
|
||||
fPoint position = GServer->RandInCircle( thisspawn->point, thisspawn->radius );
|
||||
UINT aggro = thisspawn->aggressive;
|
||||
AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit );
|
||||
thisspawn->lastRespawnTime = clock();
|
||||
thisspawn->lastRespawnTime = time(NULL);
|
||||
UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters
|
||||
thisspawn->triggercount = 0;
|
||||
}
|
||||
@@ -395,12 +398,12 @@ void CMap::RespawnMonster( )
|
||||
AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit );
|
||||
UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters
|
||||
}
|
||||
thisspawn->lastRespawnTime = clock();
|
||||
thisspawn->lastRespawnTime = time(NULL);
|
||||
thisspawn->triggercount = 0;
|
||||
}
|
||||
break;
|
||||
case 5: //sub spawns. needs to trigger from a specific montype
|
||||
if(rtime > (thisspawn->respawntime * CLOCKS_PER_SEC) && thisspawn->amon < thisspawn->max)
|
||||
if(rtime > (thisspawn->respawntime) && thisspawn->amon < thisspawn->max)
|
||||
{
|
||||
//find if any of the trigger mobs exist
|
||||
for(UINT j=0;j<MonsterList.size();j++)
|
||||
@@ -415,13 +418,13 @@ void CMap::RespawnMonster( )
|
||||
AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit );
|
||||
UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters
|
||||
thisspawn->triggercount = 0;
|
||||
thisspawn->lastRespawnTime = clock();
|
||||
thisspawn->lastRespawnTime = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if(rtime > (thisspawn->respawntime * CLOCKS_PER_SEC) && thisspawn->amon < thisspawn->max)
|
||||
if(rtime > (thisspawn->respawntime) && thisspawn->amon < thisspawn->max)
|
||||
{
|
||||
//find if any of the trigger mobs exist
|
||||
for(UINT j=0;j<MonsterList.size();j++)
|
||||
@@ -438,19 +441,19 @@ void CMap::RespawnMonster( )
|
||||
AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit );
|
||||
UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters
|
||||
}
|
||||
thisspawn->lastRespawnTime = clock();
|
||||
thisspawn->lastRespawnTime = time(NULL);
|
||||
thisspawn->triggercount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7: //TDEF spawn. Spawns thisspawn->max monsters one by one using triggercount to track them
|
||||
if(rtime > (thisspawn->respawntime * CLOCKS_PER_SEC) && thisspawn->triggercount < thisspawn->max)
|
||||
if(rtime > (thisspawn->respawntime) && thisspawn->triggercount < thisspawn->max)
|
||||
{
|
||||
fPoint position = GServer->RandInCircle( thisspawn->point, thisspawn->radius );
|
||||
AddMonster( thisspawn->montype, position, 0, thisspawn->id, 0, true, 0 );
|
||||
UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 3); // update the counters
|
||||
thisspawn->lastRespawnTime = clock();
|
||||
thisspawn->lastRespawnTime = time(NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -463,8 +466,8 @@ void CMap::RespawnMonster( )
|
||||
for (UINT j = 0; j < MobGroupList.size(); j++)
|
||||
{
|
||||
CMobGroup* thisgroup = MobGroupList.at(j);
|
||||
clock_t rtime = clock() - thisgroup->lastRespawnTime;
|
||||
if (rtime < thisgroup->respawntime*CLOCKS_PER_SEC || thisgroup->active >= thisgroup->limit)
|
||||
time_t rtime = time(NULL) - thisgroup->lastRespawnTime;
|
||||
if (rtime < thisgroup->respawntime || thisgroup->active >= thisgroup->limit)
|
||||
continue;
|
||||
for (UINT k = thisgroup->active; k < thisgroup->limit; k++)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user