1
0
Fork 0

Fix sending incorrect date values on world change

Yak shave: make more things use cTickTime. Fix a couple of incorrect modulo-on-millisecond-value by making them use WorldTickAge.
This commit is contained in:
Tiger Wang 2021-04-05 01:38:43 +01:00
parent a2a2226179
commit 4cd49d7eca
37 changed files with 322 additions and 198 deletions

View File

@ -9138,24 +9138,6 @@ a_Player:OpenWindow(Window);
},
Notes = "Returns the relative walk speed of this mob. Standard is 1.0",
},
GetSpawnDelay =
{
IsStatic = true,
Params =
{
{
Name = "MobFamily",
Type = "cMonster#eFamily",
},
},
Returns =
{
{
Type = "number",
},
},
Notes = "Returns the spawn delay - the number of game ticks between spawn attempts - for the specified mob family.",
},
HasCustomName =
{
Returns =
@ -11392,10 +11374,6 @@ a_Player:OpenWindow(Window);
},
Constants =
{
EATING_TICKS =
{
Notes = "Number of ticks required for consuming an item.",
},
MAX_FOOD_LEVEL =
{
Notes = "The maximum food level value. When the food level is at this value, the player cannot eat.",

View File

@ -1076,10 +1076,6 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
{
Notes = "Width (X) of the internal {{cItemGrid}} representing the hopper contents.",
},
TICKS_PER_TRANSFER =
{
Notes = "Number of ticks between when the hopper transfers items.",
},
},
Inherits = "cBlockEntityWithItems",
},

View File

@ -2338,6 +2338,36 @@ static int tolua_cClientHandle_SendPluginMessage(lua_State * L)
static int tolua_cClientHandle_SendTimeUpdate(lua_State * L)
{
cLuaState S(L);
if (
!S.CheckParamSelf("cClientHandle") ||
!S.CheckParamNumber(2, 3) ||
!S.CheckParamBool(4) ||
!S.CheckParamEnd(5)
)
{
return 0;
}
cClientHandle * Client;
cTickTimeLong::rep WorldAge, WorldDate;
bool DoDayLightCycle;
S.GetStackValues(1, Client, WorldAge, WorldDate, DoDayLightCycle);
if (Client == nullptr)
{
return S.ApiParamError("Invalid 'self'");
}
Client->SendTimeUpdate(cTickTimeLong(WorldAge), cTickTimeLong(WorldDate), DoDayLightCycle);
return 0;
}
static int tolua_cClientHandle_GetForgeMods(lua_State * L)
{
cLuaState S(L);
@ -4361,6 +4391,7 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "GetForgeMods", tolua_cClientHandle_GetForgeMods);
tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage);
tolua_function(tolua_S, "SendTimeUpdate", tolua_cClientHandle_SendTimeUpdate);
tolua_function(tolua_S, "GetUUID", tolua_cClientHandle_GetUUID);
tolua_function(tolua_S, "GenerateOfflineUUID", tolua_cClientHandle_GenerateOfflineUUID);
tolua_function(tolua_S, "IsUUIDOnline", tolua_cClientHandle_IsUUIDOnline);

View File

@ -1266,6 +1266,70 @@ static int tolua_cWorld_GetSignLines(lua_State * tolua_S)
static int tolua_cWorld_GetTimeOfDay(lua_State * tolua_S)
{
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamSelf("cWorld") ||
!L.CheckParamEnd(2)
)
{
return 0;
}
// Get params:
cWorld * Self = nullptr;
L.GetStackValues(1, Self);
if (Self == nullptr)
{
return L.ApiParamError("Invalid 'self'");
}
// Call the function:
const auto Time = Self->GetTimeOfDay();
// Push the returned value:
L.Push(Time.count());
return 1;
}
static int tolua_cWorld_GetWorldAge(lua_State * tolua_S)
{
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamSelf("cWorld") ||
!L.CheckParamEnd(2)
)
{
return 0;
}
// Get params:
cWorld * Self = nullptr;
L.GetStackValues(1, Self);
if (Self == nullptr)
{
return L.ApiParamError("Invalid 'self'");
}
// Call the function:
const auto Time = Self->GetWorldAge();
// Push the returned value:
L.Push(static_cast<lua_Number>(Time.count()));
return 1;
}
static int tolua_cWorld_PrepareChunk(lua_State * tolua_S)
{
/* Function signature:
@ -1459,6 +1523,37 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
static int tolua_cWorld_SetTimeOfDay(lua_State * tolua_S)
{
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamSelf("cWorld") ||
!L.CheckParamNumber(2) ||
!L.CheckParamEnd(3)
)
{
return 0;
}
// Get params:
cWorld * Self = nullptr;
cTickTime::rep Time;
L.GetStackValues(1, Self, Time);
if (Self == nullptr)
{
return L.ApiParamError("Invalid 'self'");
}
// Call the function:
Self->SetTimeOfDay(cTickTime(Time));
return 0;
}
static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
{
// Function signature:
@ -1490,7 +1585,7 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not store the callback parameter");
}
World->ScheduleTask(NumTicks, [Task](cWorld & a_World)
World->ScheduleTask(cTickTime(NumTicks), [Task](cWorld & a_World)
{
Task->Call(&a_World);
}
@ -1624,17 +1719,16 @@ void cManualBindings::BindWorld(lua_State * tolua_S)
tolua_function(tolua_S, "GetBlockSkyLight", tolua_cWorld_GetBlockSkyLight);
tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta);
tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines);
tolua_function(tolua_S, "GetTimeOfDay", tolua_cWorld_GetTimeOfDay);
tolua_function(tolua_S, "GetWorldAge", tolua_cWorld_GetWorldAge);
tolua_function(tolua_S, "PrepareChunk", tolua_cWorld_PrepareChunk);
tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask);
tolua_function(tolua_S, "ScheduleTask", tolua_cWorld_ScheduleTask);
tolua_function(tolua_S, "SetBlock", tolua_cWorld_SetBlock);
tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines);
tolua_function(tolua_S, "SetTimeOfDay", tolua_cWorld_SetTimeOfDay);
tolua_function(tolua_S, "SpawnSplitExperienceOrbs", tolua_cWorld_SpawnSplitExperienceOrbs);
tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight);
tolua_endmodule(tolua_S);
tolua_endmodule(tolua_S);
}

View File

@ -541,7 +541,7 @@ bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVec
if (world != nullptr)
{
worldName = world->GetName();
worldAge = world->GetWorldAge();
worldAge = world->GetWorldAge().count();
}
else
{

View File

@ -296,8 +296,10 @@ void cBeaconEntity::SendTo(cClientHandle & a_Client)
bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
// Update the beacon every 4 seconds
if ((GetWorld()->GetWorldAge() % 80) == 0)
using namespace std::chrono_literals;
// Update the beacon every 4 seconds:
if ((GetWorld()->GetWorldTickAge() % 4s) == 0s)
{
UpdateBeacon();
GiveEffects();

View File

@ -288,8 +288,8 @@ void cBrewingstandEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
void cBrewingstandEntity::UpdateProgressBars(bool a_ForceUpdate)
{
/** Sending an update every 3th tick, using a higher value lets look the progressbar ugly */
if (!a_ForceUpdate && (m_World->GetWorldAge() % 3 != 0))
// Send an update every 3rd tick, using a higher value makes the progressbar look ugly:
if (!a_ForceUpdate && ((m_World->GetWorldTickAge() % 3_tick) != 0_tick))
{
return;
}

View File

@ -388,8 +388,8 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const
void cFurnaceEntity::UpdateProgressBars(bool a_ForceUpdate)
{
// In order to preserve bandwidth, an update is sent only every 10th tick
if (!a_ForceUpdate && (m_World->GetWorldAge() % 10 != 0))
// In order to preserve bandwidth, an update is sent only every 10th tick:
if (!a_ForceUpdate && ((m_World->GetWorldTickAge() % 10_tick) != 0_tick))
{
return;
}

View File

@ -17,6 +17,13 @@
// How many ticks at minimum between two item transfers to or from the hopper.
#define TICKS_PER_TRANSFER 8_tick
cHopperEntity::cHopperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
Super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World),
m_LastMoveItemsInTick(0),
@ -76,14 +83,14 @@ void cHopperEntity::CopyFrom(const cBlockEntity & a_Src)
bool cHopperEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
UNUSED(a_Dt);
Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge();
bool isDirty = false;
if (!m_Locked)
{
isDirty = MoveItemsIn (a_Chunk, CurrentTick) || isDirty;
isDirty = MovePickupsIn(a_Chunk, CurrentTick) || isDirty;
isDirty = MoveItemsOut (a_Chunk, CurrentTick) || isDirty;
const auto CurrentTick = a_Chunk.GetWorld()->GetWorldAge();
isDirty = MoveItemsIn(a_Chunk, CurrentTick) || isDirty;
isDirty = MovePickupsIn(a_Chunk) || isDirty;
isDirty = MoveItemsOut(a_Chunk, CurrentTick) || isDirty;
}
return isDirty;
}
@ -147,7 +154,7 @@ void cHopperEntity::OpenNewWindow(void)
bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, const cTickTimeLong a_CurrentTick)
{
if (m_Pos.y >= cChunkDef::Height)
{
@ -155,7 +162,7 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
return false;
}
if (a_CurrentTick - m_LastMoveItemsInTick < TICKS_PER_TRANSFER)
if ((a_CurrentTick - m_LastMoveItemsInTick) < TICKS_PER_TRANSFER)
{
// Too early after the previous transfer
return false;
@ -201,10 +208,8 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk)
{
UNUSED(a_CurrentTick);
class cHopperPickupSearchCallback
{
public:
@ -290,9 +295,9 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, const cTickTimeLong a_CurrentTick)
{
if (a_CurrentTick - m_LastMoveItemsOutTick < TICKS_PER_TRANSFER)
if ((a_CurrentTick - m_LastMoveItemsOutTick) < TICKS_PER_TRANSFER)
{
// Too early after the previous transfer
return false;

View File

@ -30,8 +30,7 @@ public:
enum
{
ContentsHeight = 1,
ContentsWidth = 5,
TICKS_PER_TRANSFER = 8, ///< How many ticks at minimum between two item transfers to or from the hopper
ContentsWidth = 5
} ;
// tolua_end
@ -48,8 +47,8 @@ public:
protected:
Int64 m_LastMoveItemsInTick;
Int64 m_LastMoveItemsOutTick;
cTickTimeLong m_LastMoveItemsInTick;
cTickTimeLong m_LastMoveItemsOutTick;
// cBlockEntity overrides:
virtual void CopyFrom(const cBlockEntity & a_Src) override;
@ -61,13 +60,13 @@ protected:
void OpenNewWindow(void);
/** Moves items from the container above it into this hopper. Returns true if the contents have changed. */
bool MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick);
bool MoveItemsIn(cChunk & a_Chunk, cTickTimeLong a_CurrentTick);
/** Moves pickups from above this hopper into it. Returns true if the contents have changed. */
bool MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick);
bool MovePickupsIn(cChunk & a_Chunk);
/** Moves items out from this hopper into the destination. Returns true if the contents have changed. */
bool MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick);
bool MoveItemsOut(cChunk & a_Chunk, cTickTimeLong a_CurrentTick);
/** Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed. */
bool MoveItemsFromChest(cChunk & a_Chunk);

View File

@ -92,8 +92,10 @@ void cMobSpawnerEntity::UpdateActiveState(void)
bool cMobSpawnerEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
// Update the active flag every 5 seconds
if ((m_World->GetWorldAge() % 100) == 0)
using namespace std::chrono_literals;
// Update the active flag every 5 seconds:
if ((m_World->GetWorldTickAge() % 5s) == 0s)
{
UpdateActiveState();
}

View File

@ -75,7 +75,7 @@ bool cBlockBedHandler::OnUse(
// Sleeping is allowed only during night and thunderstorms:
if (
!(((a_WorldInterface.GetTimeOfDay() > 12541) && (a_WorldInterface.GetTimeOfDay() < 23458)) ||
!(((a_WorldInterface.GetTimeOfDay() > 12541_tick) && (a_WorldInterface.GetTimeOfDay() < 23458_tick)) ||
(a_Player.GetWorld()->GetWeather() == wThunderstorm))
) // Source: https://minecraft.gamepedia.com/Bed#Sleeping
{
@ -146,7 +146,7 @@ bool cBlockBedHandler::OnUse(
return false;
}
);
a_WorldInterface.SetTimeOfDay(0);
a_WorldInterface.SetTimeOfDay(0_tick);
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
}
return true;

View File

@ -193,7 +193,7 @@ private:
The given block type is checked when the task is executed to ensure the position still contains a button. */
static void QueueButtonRelease(cWorld & a_ButtonWorld, const Vector3i a_Position, const BLOCKTYPE a_BlockType)
{
const auto TickDelay = (a_BlockType == E_BLOCK_STONE_BUTTON) ? 20 : 30;
const auto TickDelay = (a_BlockType == E_BLOCK_STONE_BUTTON) ? 20_tick : 30_tick;
a_ButtonWorld.ScheduleTask(
TickDelay,
[a_Position, a_BlockType](cWorld & a_World)

View File

@ -56,7 +56,7 @@ void cBlockPistonHandler::ExtendPiston(Vector3i a_BlockPos, cWorld & a_World)
// However, we don't confuse animation with the underlying state of the world, so emulate by delaying 1 tick
// (Probably why vanilla has so many dupe glitches with sand and pistons lolol)
a_World.ScheduleTask(1, [a_BlockPos](cWorld & World)
a_World.ScheduleTask(1_tick, [a_BlockPos](cWorld & World)
{
BLOCKTYPE pistonBlock;
NIBBLETYPE pistonMeta;
@ -108,7 +108,7 @@ void cBlockPistonHandler::RetractPiston(Vector3i a_BlockPos, cWorld & a_World)
a_World.BroadcastBlockAction(a_BlockPos, PistonRetractAction, pistonMeta, pistonBlock);
}
a_World.ScheduleTask(1, [a_BlockPos](cWorld & World)
a_World.ScheduleTask(1_tick, [a_BlockPos](cWorld & World)
{
BLOCKTYPE pistonBlock;
NIBBLETYPE pistonMeta;

View File

@ -21,8 +21,8 @@ class cWorldInterface
public:
virtual ~cWorldInterface() {}
virtual int GetTimeOfDay(void) const = 0;
virtual Int64 GetWorldAge(void) const = 0;
virtual cTickTime GetTimeOfDay(void) const = 0;
virtual cTickTimeLong GetWorldAge(void) const = 0;
virtual eDimension GetDimension(void) const = 0;
@ -70,7 +70,7 @@ public:
If any chunk in the box is missing, ignores the entities in that chunk silently. */
virtual bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback a_Callback) = 0;
virtual void SetTimeOfDay(int a_TimeOfDay) = 0;
virtual void SetTimeOfDay(cTickTime a_TimeOfDay) = 0;
/** Returns true if it is raining or storming at the specified location. This takes into account biomes. */
virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) = 0;

View File

@ -596,7 +596,7 @@ void cWorld::BroadcastTimeUpdate(const cClientHandle * a_Exclude)
{
ForClientsInWorld(*this, a_Exclude, [&](cClientHandle & a_Client)
{
a_Client.SendTimeUpdate(GetWorldAge(), std::chrono::duration_cast<cTickTimeLong>(m_WorldDate).count(), IsDaylightCycleEnabled());
a_Client.SendTimeUpdate(GetWorldAge(), GetWorldDate(), IsDaylightCycleEnabled());
}
);
}

View File

@ -538,6 +538,8 @@ void cClientHandle::UnloadOutOfRangeChunks(void)
m_Player->GetWorld()->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkZ, this);
SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
}
m_LastUnloadCheck = m_Player->GetWorld()->GetWorldAge();
}
@ -1981,6 +1983,8 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
void cClientHandle::Tick(float a_Dt)
{
using namespace std::chrono_literals;
// anticheat fastbreak
if (m_HasStartedDigging)
{
@ -2069,8 +2073,8 @@ void cClientHandle::Tick(float a_Dt)
}
}
// Unload all chunks that are out of the view distance (every 5 seconds)
if ((m_Player->GetWorld()->GetWorldAge() % 100) == 0)
// Unload all chunks that are out of the view distance (every 5 seconds):
if ((m_Player->GetWorld()->GetWorldAge() - m_LastUnloadCheck) > 5s)
{
UnloadOutOfRangeChunks();
}
@ -3012,7 +3016,7 @@ void cClientHandle::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_
void cClientHandle::SendTimeUpdate(Int64 a_WorldAge, Int64 a_WorldDate, bool a_DoDaylightCycle)
void cClientHandle::SendTimeUpdate(const cTickTimeLong a_WorldAge, const cTickTimeLong a_WorldDate, const bool a_DoDaylightCycle)
{
m_Protocol->SendTimeUpdate(a_WorldAge, a_WorldDate, a_DoDaylightCycle);
}

View File

@ -216,7 +216,7 @@ public: // tolua_export
void SendTabCompletionResults (const AStringVector & a_Results);
void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ);
void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks); // tolua_export
void SendTimeUpdate (Int64 a_WorldAge, Int64 a_WorldDate, bool a_DoDaylightCycle); // tolua_export
void SendTimeUpdate (cTickTimeLong a_WorldAge, cTickTimeLong a_WorldDate, bool a_DoDaylightCycle);
void SendUnleashEntity (const cEntity & a_Entity);
void SendUnloadChunk (int a_ChunkX, int a_ChunkZ);
void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity);
@ -478,6 +478,9 @@ private:
int m_LastStreamedChunkX;
int m_LastStreamedChunkZ;
/** The last time UnloadOutOfRangeChunks was called. */
cTickTimeLong m_LastUnloadCheck;
/** Number of ticks since the last network packet was received (increased in Tick(), reset in OnReceivedData()) */
std::atomic<int> m_TicksSinceLastPacket;

View File

@ -103,11 +103,10 @@ void cDeadlockDetect::Execute(void)
{
// Check the world ages:
cRoot::Get()->ForEachWorld([=](cWorld & a_World)
{
CheckWorldAge(a_World.GetName(), a_World.GetWorldAge());
return false;
}
);
{
CheckWorldAge(a_World.GetName(), a_World.GetWorldAge());
return false;
});
std::this_thread::sleep_for(std::chrono::milliseconds(CYCLE_MILLISECONDS));
} // while (should run)
@ -117,7 +116,7 @@ void cDeadlockDetect::Execute(void)
void cDeadlockDetect::SetWorldAge(const AString & a_WorldName, Int64 a_Age)
void cDeadlockDetect::SetWorldAge(const AString & a_WorldName, const cTickTimeLong a_Age)
{
m_WorldAges[a_WorldName].m_Age = a_Age;
m_WorldAges[a_WorldName].m_NumCyclesSame = 0;
@ -127,7 +126,7 @@ void cDeadlockDetect::SetWorldAge(const AString & a_WorldName, Int64 a_Age)
void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age)
void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, const cTickTimeLong a_Age)
{
WorldAges::iterator itr = m_WorldAges.find(a_WorldName);
if (itr == m_WorldAges.end())
@ -157,14 +156,14 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age)
void cDeadlockDetect::DeadlockDetected(const AString & a_WorldName, Int64 a_WorldAge)
void cDeadlockDetect::DeadlockDetected(const AString & a_WorldName, const cTickTimeLong a_WorldAge)
{
LOGERROR("Deadlock detected: world %s has been stuck at age %lld. Aborting the server.",
a_WorldName.c_str(), static_cast<long long>(a_WorldAge)
a_WorldName.c_str(), static_cast<long long>(a_WorldAge.count())
);
ListTrackedCSs();
ASSERT(!"Deadlock detected");
abort();
std::abort();
}
@ -182,7 +181,3 @@ void cDeadlockDetect::ListTrackedCSs(void)
);
}
}

View File

@ -46,7 +46,7 @@ protected:
struct sWorldAge
{
/** Last m_WorldAge that has been detected in this world */
Int64 m_Age;
cTickTimeLong m_Age;
/** Number of cycles for which the age has been the same */
int m_NumCyclesSame;
@ -71,16 +71,16 @@ protected:
// cIsThread overrides:
virtual void Execute(void) override;
/** Sets the initial world age */
void SetWorldAge(const AString & a_WorldName, Int64 a_Age);
/** Sets the initial world age. */
void SetWorldAge(const AString & a_WorldName, cTickTimeLong a_Age);
/** Checks if the world's age has changed, updates the world's stats; calls DeadlockDetected() if deadlock detected */
void CheckWorldAge(const AString & a_WorldName, Int64 a_Age);
/** Checks if the world's age has changed, updates the world's stats; calls DeadlockDetected() if deadlock detected. */
void CheckWorldAge(const AString & a_WorldName, cTickTimeLong a_Age);
/** Called when a deadlock is detected in a world. Aborts the server.
a_WorldName is the name of the world whose age has triggered the detection.
a_WorldAge is the age (in ticks) in which the world is stuck. */
[[noreturn]] void DeadlockDetected(const AString & a_WorldName, Int64 a_WorldAge);
[[noreturn]] void DeadlockDetected(const AString & a_WorldName, cTickTimeLong a_WorldAge);
/** Outputs a listing of the tracked CSs, together with their name and state. */
void ListTrackedCSs();

View File

@ -46,8 +46,8 @@ void cBoat::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
// Cannot use super::BroadcastMovementUpdate here, broadcasting position when not
// expected by the client breaks things. See https://github.com/cuberite/cuberite/pull/4488
// Process packet sending every two ticks
if (GetWorld()->GetWorldAge() % 2 != 0)
// Process packet sending every two ticks:
if ((GetWorld()->GetWorldTickAge() % 2_tick) != 0_tick)
{
return;
}

View File

@ -1884,8 +1884,8 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
// Process packet sending every two ticks
if (GetWorld()->GetWorldAge() % 2 != 0)
// Process packet sending every two ticks:
if ((GetWorld()->GetWorldTickAge() % 2_tick) != 0_tick)
{
return;
}

View File

@ -59,8 +59,8 @@ const int cPlayer::MAX_HEALTH = 20;
const int cPlayer::MAX_FOOD_LEVEL = 20;
/** Number of ticks it takes to eat an item */
const int cPlayer::EATING_TICKS = 30;
// Number of ticks it takes to eat an item.
#define EATING_TICKS 30_tick
@ -530,7 +530,7 @@ void cPlayer::StartEating(void)
void cPlayer::FinishEating(void)
{
// Reset the timer:
m_EatingFinishTick = -1;
m_EatingFinishTick = -1_tick;
// Send the packets:
m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
@ -553,7 +553,7 @@ void cPlayer::FinishEating(void)
void cPlayer::AbortEating(void)
{
m_EatingFinishTick = -1;
m_EatingFinishTick = -1_tick;
m_World->BroadcastEntityMetadata(*this);
}
@ -2929,7 +2929,7 @@ void cPlayer::TickFreezeCode()
}
}
}
else if (GetWorld()->GetWorldAge() % 100 == 0)
else if ((GetWorld()->GetWorldTickAge() % 100_tick) == 0_tick)
{
// Despite the client side freeze, the player may be able to move a little by
// Jumping or canceling flight. Re-freeze every now and then
@ -3115,7 +3115,7 @@ void cPlayer::OnAddToWorld(cWorld & a_World)
m_ClientHandle->SendWeather(a_World.GetWeather());
// Send time:
m_ClientHandle->SendTimeUpdate(a_World.GetWorldAge(), a_World.GetTimeOfDay(), a_World.IsDaylightCycleEnabled());
m_ClientHandle->SendTimeUpdate(a_World.GetWorldAge(), a_World.GetWorldDate(), a_World.IsDaylightCycleEnabled());
// Finally, deliver the notification hook:
cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*this);
@ -3298,7 +3298,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
m_World->CollectPickupsByPlayer(*this);
if ((m_EatingFinishTick >= 0) && (m_EatingFinishTick <= m_World->GetWorldAge()))
if ((m_EatingFinishTick >= 0_tick) && (m_EatingFinishTick <= m_World->GetWorldAge()))
{
FinishEating();
}

View File

@ -86,9 +86,6 @@ public:
static const int MAX_FOOD_LEVEL;
/** Number of ticks it takes to eat an item */
static const int EATING_TICKS;
// tolua_end
CLASS_PROTODEF(cPlayer)
@ -371,7 +368,7 @@ public:
void AddFoodExhaustion(double a_Exhaustion);
/** Returns true if the player is currently in the process of eating the currently equipped item */
bool IsEating(void) const { return (m_EatingFinishTick >= 0); }
bool IsEating(void) const { return m_EatingFinishTick >= 0_tick; }
/** Returns true if the player is currently flying */
bool IsFlying(void) const { return m_IsFlying; }
@ -734,7 +731,7 @@ private:
bool m_IsVisible;
/** The world tick in which eating will be finished. -1 if not eating */
Int64 m_EatingFinishTick;
cTickTimeLong m_EatingFinishTick;
/** Player Xp level */
int m_LifetimeTotalXp;

View File

@ -338,14 +338,14 @@ T Clamp(T a_Value, T a_Min, T a_Max)
/** Floors a value, then casts it to C (an int by default) */
/** Floors a value, then casts it to C (an int by default). */
template <typename C = int, typename T>
typename std::enable_if<std::is_arithmetic<T>::value, C>::type FloorC(T a_Value)
{
return static_cast<C>(std::floor(a_Value));
}
/** Ceils a value, then casts it to C (an int by default) */
/** Ceils a value, then casts it to C (an int by default). */
template <typename C = int, typename T>
typename std::enable_if<std::is_arithmetic<T>::value, C>::type CeilC(T a_Value)
{
@ -356,9 +356,17 @@ typename std::enable_if<std::is_arithmetic<T>::value, C>::type CeilC(T a_Value)
// a tick is 50 ms
using cTickTime = std::chrono::duration<int, std::ratio_multiply<std::chrono::milliseconds::period, std::ratio<50>>>;
using cTickTimeLong = std::chrono::duration<Int64, cTickTime::period>;
// A time duration representing a Minecraft tick (50 ms), capable of storing at least 32'767 ticks.
using cTickTime = std::chrono::duration<signed int, std::ratio_multiply<std::chrono::milliseconds::period, std::ratio<50>>>;
// A time duration representing a Minecraft tick (50 ms), capable of storing at least a 64 bit signed duration.
using cTickTimeLong = std::chrono::duration<signed long long int, cTickTime::period>;
/** Converts a literal to a tick time. */
constexpr cTickTimeLong operator ""_tick(const unsigned long long a_Ticks)
{
return cTickTimeLong(a_Ticks);
}
using ContiguousByteBuffer = std::basic_string<std::byte>;
using ContiguousByteBufferView = std::basic_string_view<std::byte>;

View File

@ -39,7 +39,6 @@ int cMobCensus::GetCapMultiplier(cMonster::eFamily a_MobFamily)
case cMonster::mfAmbient: return 16;
case cMonster::mfWater: return 5;
case cMonster::mfNoSpawn:
case cMonster::mfUnhandled:
{
break;
}

View File

@ -25,7 +25,7 @@ void cCaveSpider::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
return;
}
m_EMPersonality = (GetWorld()->GetTimeOfDay() < (12000 + 1000)) ? PASSIVE : AGGRESSIVE;
m_EMPersonality = (GetWorld()->GetTimeOfDay() < 13000_tick) ? PASSIVE : AGGRESSIVE;
}

View File

@ -1150,34 +1150,26 @@ cMonster::eFamily cMonster::FamilyFromType(eMonsterType a_Type)
case mtZombieHorse: return mfPassive;
case mtZombiePigman: return mfHostile;
case mtZombieVillager: return mfHostile;
default:
{
ASSERT(!"Unhandled mob type");
return mfUnhandled;
}
case mtInvalidType: break;
}
UNREACHABLE("Unhandled mob type");
}
int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily)
cTickTime cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily)
{
switch (a_MobFamily)
{
case mfHostile: return 40;
case mfPassive: return 40;
case mfAmbient: return 40;
case mfWater: return 400;
case mfNoSpawn: return -1;
default:
{
ASSERT(!"Unhandled mob family");
return -1;
}
case mfHostile: return 40_tick;
case mfPassive: return 40_tick;
case mfAmbient: return 40_tick;
case mfWater: return 400_tick;
case mfNoSpawn: return -1_tick;
}
UNREACHABLE("Unhandled mob family");
}
@ -1654,7 +1646,7 @@ bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
if (
(Chunk->GetBlock(Rel) != E_BLOCK_SOULSAND) && // Not on soulsand
(GetWorld()->GetTimeOfDay() < 12000 + 1000) && // Daytime
(GetWorld()->GetTimeOfDay() < 13000_tick) && // Daytime
Chunk->IsWeatherSunnyAt(Rel.x, Rel.z) && // Not raining
!IsInWater() // Isn't swimming
)

View File

@ -32,8 +32,7 @@ public:
mfAmbient = 2, // Bats
mfWater = 3, // Squid, Guardian
mfNoSpawn,
mfUnhandled, // Nothing. Be sure this is the last and the others are in order
mfNoSpawn
} ;
// tolua_end
@ -187,11 +186,11 @@ public:
/** Returns the mob family based on the type */
static eFamily FamilyFromType(eMonsterType a_MobType);
/** Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family */
static int GetSpawnDelay(cMonster::eFamily a_MobFamily);
// tolua_end
/** Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family */
static cTickTime GetSpawnDelay(cMonster::eFamily a_MobFamily);
/** Translates the MobType enum to the vanilla nbt name */
static AString MobTypeToVanillaNBT(eMonsterType a_MobType);

View File

@ -438,7 +438,7 @@ public:
virtual void SendTabCompletionResults (const AStringVector & a_Results) = 0;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) = 0;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_WorldDate, bool a_DoDaylightCycle) = 0;
virtual void SendTimeUpdate (cTickTimeLong a_WorldAge, cTickTimeLong a_WorldDate, bool a_DoDaylightCycle) = 0;
virtual void SendUnleashEntity (const cEntity & a_Entity) = 0;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0;

View File

@ -1566,20 +1566,23 @@ void cProtocol_1_8_0::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int
void cProtocol_1_8_0::SendTimeUpdate(Int64 a_WorldAge, Int64 a_WorldDate, bool a_DoDaylightCycle)
void cProtocol_1_8_0::SendTimeUpdate(const cTickTimeLong a_WorldAge, const cTickTimeLong a_WorldDate, const bool a_DoDaylightCycle)
{
ASSERT(m_State == 3); // In game mode?
if (!a_DoDaylightCycle)
cPacketizer Pkt(*this, pktTimeUpdate);
Pkt.WriteBEInt64(a_WorldAge.count());
if (a_DoDaylightCycle)
{
Pkt.WriteBEInt64(a_WorldDate.count());
}
else
{
// Negating the date stops time from advancing on the client
// (the std::min construction is to handle the case where the date is exactly zero):
a_WorldDate = std::min(-a_WorldDate, -1LL);
Pkt.WriteBEInt64(std::min(-a_WorldDate.count(), -1LL));
}
cPacketizer Pkt(*this, pktTimeUpdate);
Pkt.WriteBEInt64(a_WorldAge);
Pkt.WriteBEInt64(a_WorldDate);
}

View File

@ -119,7 +119,7 @@ public:
virtual void SendTabCompletionResults (const AStringVector & a_Results) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_WorldDate, bool a_DoDaylightCycle) override;
virtual void SendTimeUpdate (cTickTimeLong a_WorldAge, cTickTimeLong a_WorldDate, bool a_DoDaylightCycle) override;
virtual void SendUnleashEntity (const cEntity & a_Entity) override;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;

View File

@ -18,7 +18,7 @@ namespace DaylightSensorHandler
}
// The [0, 1) proportion of the current day that has elapsed.
const auto ProportionOfDay = a_Chunk.GetWorld()->GetTimeOfDay() * (static_cast<float>(M_PI) / 12000.f);
const auto ProportionOfDay = a_Chunk.GetWorld()->GetTimeOfDay().count() * (static_cast<float>(M_PI) / 12000.f);
// The curved value of darkened skylight, with outputs somewhat similar to Vanilla.
const auto RawOutput = a_Chunk.GetSkyLightAltered(a_Position) * (0.6f * std::sin(ProportionOfDay) + 0.5f);

View File

@ -108,7 +108,7 @@ cWorld::cTickThread::cTickThread(cWorld & a_World) :
void cWorld::cTickThread::Execute(void)
{
auto LastTime = std::chrono::steady_clock::now();
auto TickTime = std::chrono::duration_cast<std::chrono::milliseconds>(cTickTime(1));
auto TickTime = std::chrono::duration_cast<std::chrono::milliseconds>(1_tick);
while (!m_ShouldTerminate)
{
@ -117,10 +117,10 @@ void cWorld::cTickThread::Execute(void)
m_World.Tick(WaitTime, TickTime);
TickTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - NowTime);
if (TickTime < cTickTime(1))
if (TickTime < 1_tick)
{
// Stretch tick time until it's at least 1 tick
std::this_thread::sleep_for(cTickTime(1) - TickTime);
// Stretch tick time until it's at least 1 tick:
std::this_thread::sleep_for(1_tick - TickTime);
}
LastTime = NowTime;
@ -404,7 +404,7 @@ cWorld::cWorld(
cComposableGenerator::InitializeGeneratorDefaults(IniFile, m_Dimension);
InitializeAndLoadMobSpawningValues(IniFile);
SetTimeOfDay(IniFile.GetValueSetI("General", "TimeInTicks", GetTimeOfDay()));
m_WorldDate = cTickTime(IniFile.GetValueSetI("General", "TimeInTicks", GetWorldDate().count()));
// preallocate some memory for ticking blocks so we don't need to allocate that often
m_BlockTickQueue.reserve(1000);
@ -434,10 +434,10 @@ cWorld::cWorld(
}
// Init of the spawn monster time (as they are supposed to have different spawn rate)
m_LastSpawnMonster.emplace(cMonster::mfHostile, cTickTimeLong(0));
m_LastSpawnMonster.emplace(cMonster::mfPassive, cTickTimeLong(0));
m_LastSpawnMonster.emplace(cMonster::mfAmbient, cTickTimeLong(0));
m_LastSpawnMonster.emplace(cMonster::mfWater, cTickTimeLong(0));
m_LastSpawnMonster.emplace(cMonster::mfHostile, 0_tick);
m_LastSpawnMonster.emplace(cMonster::mfPassive, 0_tick);
m_LastSpawnMonster.emplace(cMonster::mfAmbient, 0_tick);
m_LastSpawnMonster.emplace(cMonster::mfWater, 0_tick);
}
@ -475,31 +475,49 @@ void cWorld::CastThunderbolt(Vector3i a_Block)
int cWorld::GetTimeOfDay(void) const
cTickTime cWorld::GetTimeOfDay(void) const
{
using namespace std::chrono_literals;
return std::chrono::duration_cast<cTickTime>(m_WorldDate % 20min).count();
return std::chrono::duration_cast<cTickTime>(m_WorldDate % 20min);
}
Int64 cWorld::GetWorldAge(void) const
cTickTimeLong cWorld::GetWorldAge(void) const
{
return std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count();
return std::chrono::duration_cast<cTickTimeLong>(m_WorldAge);
}
void cWorld::SetTimeOfDay(int a_TimeOfDay)
cTickTimeLong cWorld::GetWorldDate() const
{
return std::chrono::duration_cast<cTickTimeLong>(m_WorldDate);
}
cTickTimeLong cWorld::GetWorldTickAge() const
{
return m_WorldTickAge;
}
void cWorld::SetTimeOfDay(const cTickTime a_TimeOfDay)
{
using namespace std::chrono_literals;
m_WorldDate = (m_WorldDate / 20min) * 20min + cTickTime(a_TimeOfDay);
m_WorldDate = (m_WorldDate / 20min) * 20min + a_TimeOfDay;
UpdateSkyDarkness();
BroadcastTimeUpdate();
}
@ -955,7 +973,7 @@ void cWorld::Stop(cDeadlockDetect & a_DeadlockDetect)
IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes);
IniFile.SetValueB("General", "IsDaylightCycleEnabled", m_IsDaylightCycleEnabled);
IniFile.SetValueI("General", "Weather", static_cast<int>(m_Weather));
IniFile.SetValueI("General", "TimeInTicks", GetTimeOfDay());
IniFile.SetValueI("General", "TimeInTicks", GetWorldDate().count());
IniFile.SetValueI("General", "WorldAgeMS", static_cast<Int64>(m_WorldAge.count()));
IniFile.WriteFile(m_IniFileName);
@ -988,7 +1006,7 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La
cPluginManager::Get()->CallHookWorldTick(*this, a_Dt, a_LastTickDurationMSec);
m_WorldAge += a_Dt;
m_WorldTickAge += 1;
m_WorldTickAge++;
if (m_IsDaylightCycleEnabled)
{
@ -998,14 +1016,14 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La
UpdateSkyDarkness();
// Broadcast time update every 64 ticks (3.2 seconds):
if ((m_WorldTickAge % 64) == 0)
if ((m_WorldTickAge % 64_tick) == 0_tick)
{
BroadcastTimeUpdate();
}
}
// Broadcast player list pings every 256 ticks (12.8 seconds):
if ((m_WorldTickAge % 256) == 0)
if ((m_WorldTickAge % 256_tick) == 0_tick)
{
BroadcastPlayerListUpdatePing();
}
@ -1098,15 +1116,14 @@ void cWorld::TickMobs(std::chrono::milliseconds a_Dt)
for (size_t i = 0; i < ARRAYCOUNT(AllFamilies); i++)
{
cMonster::eFamily Family = AllFamilies[i];
cTickTime SpawnDelay = cTickTime(cMonster::GetSpawnDelay(Family));
if (
(m_LastSpawnMonster[Family] > m_WorldAge - SpawnDelay) || // Not reached the needed ticks before the next round
(m_LastSpawnMonster[Family] > (m_WorldTickAge - cMonster::GetSpawnDelay(Family))) || // Not reached the needed ticks before the next round
MobCensus.IsCapped(Family)
)
{
continue;
}
m_LastSpawnMonster[Family] = std::chrono::duration_cast<cTickTimeLong>(m_WorldAge);
m_LastSpawnMonster[Family] = m_WorldTickAge;
cMobSpawner Spawner(Family, m_AllowedMobs);
if (Spawner.CanSpawnAnything())
{
@ -1258,11 +1275,9 @@ void cWorld::TickQueuedTasks(void)
// Partition everything to be executed by returning false to move to end of list if time reached
auto MoveBeginIterator = std::partition(m_Tasks.begin(), m_Tasks.end(), [this](const decltype(m_Tasks)::value_type & a_Task)
{
const auto WorldAgeTicks = std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count();
return (a_Task.first >= WorldAgeTicks);
}
);
{
return a_Task.first >= m_WorldAge;
});
// Cut all the due tasks from m_Tasks into Tasks:
Tasks.insert(
@ -1286,11 +1301,11 @@ void cWorld::TickQueuedTasks(void)
void cWorld::UpdateSkyDarkness(void)
{
const int TIME_SUNSET = 12000;
const int TIME_NIGHT_START = 13187;
const int TIME_NIGHT_END = 22812;
const int TIME_SUNRISE = 23999;
const int TIME_SPAWN_DIVISOR = 148;
const auto TIME_SUNSET = 12000_tick;
const auto TIME_NIGHT_START = 13187_tick;
const auto TIME_NIGHT_END = 22812_tick;
const auto TIME_SUNRISE = 23999_tick;
const auto TIME_SPAWN_DIVISOR = 148_tick;
const auto TempTime = GetTimeOfDay();
if (TempTime <= TIME_SUNSET)
@ -1448,7 +1463,7 @@ bool cWorld::GrowTreeFromSapling(Vector3i a_BlockPos)
{
cNoise Noise(m_Generator.GetSeed());
sSetBlockVector Logs, Other;
auto WorldAge = static_cast<int>(std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count() & 0xffffffff);
auto WorldAge = static_cast<int>(m_WorldTickAge.count() & 0xffffffff);
auto SaplingMeta = GetBlockMeta(a_BlockPos);
switch (SaplingMeta & 0x07)
{
@ -1577,7 +1592,7 @@ bool cWorld::GrowTreeByBiome(const Vector3i a_BlockPos)
{
cNoise Noise(m_Generator.GetSeed());
sSetBlockVector Logs, Other;
auto seq = static_cast<int>(std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count() & 0xffffffff);
auto seq = static_cast<int>(m_WorldTickAge.count() & 0xffffffff);
GetTreeImageByBiome(a_BlockPos, Noise, seq, GetBiomeAt(a_BlockPos.x, a_BlockPos.z), Logs, Other);
Other.insert(Other.begin(), Logs.begin(), Logs.end());
Logs.clear();
@ -2192,7 +2207,7 @@ bool cWorld::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const
void cWorld::UnloadUnusedChunks(void)
{
m_LastChunkCheck = std::chrono::duration_cast<cTickTimeLong>(m_WorldAge);
m_LastChunkCheck = m_WorldAge;
m_ChunkMap.UnloadUnusedChunks();
}
@ -2668,7 +2683,7 @@ void cWorld::SaveAllChunks(void)
{
if (IsSavingEnabled())
{
m_LastSave = std::chrono::duration_cast<cTickTimeLong>(m_WorldAge);
m_LastSave = m_WorldAge;
m_ChunkMap.SaveAllChunks();
}
}
@ -2696,9 +2711,9 @@ void cWorld::QueueTask(std::function<void(cWorld &)> a_Task)
void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Task)
void cWorld::ScheduleTask(const cTickTime a_DelayTicks, std::function<void (cWorld &)> a_Task)
{
Int64 TargetTick = a_DelayTicks + std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count();
const auto TargetTick = a_DelayTicks + m_WorldAge;
// Insert the task into the list of scheduled tasks
{

View File

@ -106,16 +106,11 @@ public:
BroadcastTimeUpdate();
}
virtual int GetTimeOfDay(void) const override;
virtual Int64 GetWorldAge(void) const override;
void SetTicksUntilWeatherChange(int a_WeatherInterval)
{
m_WeatherInterval = a_WeatherInterval;
}
virtual void SetTimeOfDay(int a_TimeOfDay) override;
/** Returns the default weather interval for the specific weather type.
Returns -1 for any unknown weather. */
int GetDefaultWeatherInterval(eWeather a_Weather) const;
@ -150,6 +145,13 @@ public:
// tolua_end
virtual cTickTime GetTimeOfDay(void) const override;
virtual cTickTimeLong GetWorldAge(void) const override;
cTickTimeLong GetWorldDate() const;
cTickTimeLong GetWorldTickAge() const;
virtual void SetTimeOfDay(cTickTime a_TimeOfDay) override;
/** Retrieves the world height at the specified coords; returns false if chunk not loaded / generated */
bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp
@ -754,7 +756,7 @@ public:
void QueueTask(std::function<void(cWorld &)> a_Task); // Exported in ManualBindings.cpp
/** Queues a lambda task onto the tick thread, with the specified delay. */
void ScheduleTask(int a_DelayTicks, std::function<void(cWorld &)> a_Task);
void ScheduleTask(cTickTime a_DelayTicks, std::function<void(cWorld &)> a_Task);
/** Returns the number of chunks loaded */
size_t GetNumChunks() const; // tolua_export
@ -993,10 +995,10 @@ private:
/** The time since this world began, in ticks.
Monotonic, but does not persist across restarts.
Used for less important but heavy tasks that run periodically. These tasks don't need to follow wallclock time, and slowing their rate down if TPS drops is desirable. */
unsigned long long m_WorldTickAge;
cTickTimeLong m_WorldTickAge;
cTickTimeLong m_LastChunkCheck; // The last WorldAge (in ticks) in which unloading and possibly saving was triggered
cTickTimeLong m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred
std::chrono::milliseconds m_LastChunkCheck; // The last WorldAge in which unloading and possibly saving was triggered.
std::chrono::milliseconds m_LastSave; // The last WorldAge in which save-all was triggerred.
std::map<cMonster::eFamily, cTickTimeLong> m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned (for each megatype of monster) // MG TODO : find a way to optimize without creating unmaintenability (if mob IDs are becoming unrowed)
NIBBLETYPE m_SkyDarkness;
@ -1093,7 +1095,7 @@ private:
cCriticalSection m_CSTasks;
/** Tasks that have been queued onto the tick thread, possibly to be executed at target tick in the future; guarded by m_CSTasks */
std::vector<std::pair<Int64, std::function<void(cWorld &)>>> m_Tasks;
std::vector<std::pair<std::chrono::milliseconds, std::function<void(cWorld &)>>> m_Tasks;
/** Guards m_EntitiesToAdd */
cCriticalSection m_CSEntitiesToAdd;

View File

@ -1252,7 +1252,7 @@ void NBTChunkSerializer::Serialize(const cWorld & aWorld, cChunkCoords aCoords,
}
// Save the world age to the chunk data. Required by vanilla and mcedit.
aWriter.AddLong("LastUpdate", aWorld.GetWorldAge());
aWriter.AddLong("LastUpdate", aWorld.GetWorldAge().count());
// Store the flag that the chunk has all the ores, trees, dungeons etc. Cuberite chunks are always complete.
aWriter.AddByte("TerrainPopulated", 1);

View File

@ -109,8 +109,8 @@ cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) :
Writer.AddInt("SpawnY", FloorC(a_World->GetSpawnY()));
Writer.AddInt("SpawnZ", FloorC(a_World->GetSpawnZ()));
Writer.AddInt("version", 19133);
Writer.AddLong("DayTime", a_World->GetTimeOfDay());
Writer.AddLong("Time", a_World->GetWorldAge());
Writer.AddLong("DayTime", a_World->GetWorldDate().count());
Writer.AddLong("Time", a_World->GetWorldAge().count());
Writer.AddLong("SizeOnDisk", 0);
Writer.AddString("generatorName", "default");
Writer.AddString("generatorOptions", "");