1
0

Only store IDs across ticks

This commit is contained in:
Tiger Wang
2020-04-05 13:41:14 +01:00
parent 63adc6d7dc
commit e98f93a079
4 changed files with 65 additions and 29 deletions

View File

@@ -73,6 +73,7 @@ cEntity::cEntity(eEntityType a_EntityType, Vector3d a_Pos, double a_Width, doubl
m_Height(a_Height),
m_InvulnerableTicks(0)
{
m_WorldChangeInfo.m_NewWorld = nullptr;
}
@@ -1406,7 +1407,7 @@ bool cEntity::DetectPortal()
cWorld * TargetWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedOverworldName());
ASSERT(TargetWorld != nullptr); // The linkage checker should have prevented this at startup. See cWorld::start()
LOGD("Jumping %s -> %s", DimensionToString(dimNether).c_str(), DimensionToString(DestionationDim).c_str());
new cNetherPortalScanner(this, TargetWorld, TargetPos, cChunkDef::Height);
new cNetherPortalScanner(*this, TargetWorld, TargetPos, cChunkDef::Height);
return true;
}
// Nether portal in the overworld
@@ -1438,7 +1439,7 @@ bool cEntity::DetectPortal()
cWorld * TargetWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedNetherWorldName());
ASSERT(TargetWorld != nullptr); // The linkage checker should have prevented this at startup. See cWorld::start()
LOGD("Jumping %s -> %s", DimensionToString(dimOverworld).c_str(), DimensionToString(DestionationDim).c_str());
new cNetherPortalScanner(this, TargetWorld, TargetPos, (cChunkDef::Height / 2));
new cNetherPortalScanner(*this, TargetWorld, TargetPos, (cChunkDef::Height / 2));
return true;
}
}
@@ -1587,26 +1588,47 @@ bool cEntity::MoveToWorld(cWorld * a_World, Vector3d a_NewPosition, bool a_SetPo
return false;
}
// Create new world change info
auto NewWCI = cpp14::make_unique<sWorldChangeInfo>();
*NewWCI = { a_World, a_NewPosition, a_SetPortalCooldown, a_ShouldSendRespawn };
// Publish atomically
auto OldWCI = m_WorldChangeInfo.exchange(std::move(NewWCI));
if (OldWCI == nullptr)
if (m_WorldChangeInfo.m_NewWorld != nullptr)
{
// Schedule a new world change.
GetWorld()->QueueTask(
[this](cWorld & a_CurWorld)
{
auto WCI = m_WorldChangeInfo.exchange(nullptr);
cWorld::cLock Lock(a_CurWorld);
DoMoveToWorld(*WCI);
}
);
// Avoid scheduling multiple warp tasks
return true;
}
// Create new world change info
m_WorldChangeInfo = { a_World, a_NewPosition, a_SetPortalCooldown, a_ShouldSendRespawn };
// TODO: move to capture when C++14
const auto EntityID = GetUniqueID();
/* Requirements:
Only one world change in-flight at any time
No ticking during world changes
The last invocation takes effect
As of writing, cWorld ticks entities, clients, and then processes tasks
We may call MoveToWorld (any number of times - consider multiple /portal commands within a tick) in the first and second stages
Queue a task onto the third stage to invoke DoMoveToWorld ONCE with the last given destination world
Store entity IDs in case client tick found the player disconnected and immediately destroys the object
After the move begins, no further calls to MoveToWorld is possible since neither the client nor entity is ticked
This remains until the warp is complete and the destination world resumes ticking.
*/
GetWorld()->QueueTask(
[EntityID](cWorld & a_CurWorld)
{
a_CurWorld.DoWithEntityByID(
EntityID,
[](cEntity & a_Entity)
{
auto & WCI = a_Entity.m_WorldChangeInfo;
a_Entity.DoMoveToWorld(WCI);
WCI.m_NewWorld = nullptr;
return true;
}
);
}
);
return true;
}