From 41618bf242e66744431a1d28e0409f543fb240e4 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 19 Jan 2014 23:49:19 +0100 Subject: [PATCH] Changed the cWorld::ScheduleTask() signature. Now it takes the delay in ticks as an argument, and a cTask descendant as the task to run. Lua API has been updated similarly. --- MCServer/Plugins/Debuggers/Debuggers.lua | 40 ++++ src/Bindings/ManualBindings.cpp | 26 ++- src/World.cpp | 32 ++- src/World.h | 276 ++++++++++++----------- 4 files changed, 222 insertions(+), 152 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 8512fbd5f..2d2d2736d 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -52,6 +52,7 @@ function Initialize(Plugin) PM:BindCommand("/fill", "debuggers", HandleFill, "- Fills all block entities in current chunk with junk"); PM:BindCommand("/fr", "debuggers", HandleFurnaceRecipe, "- Shows the furnace recipe for the currently held item"); PM:BindCommand("/ff", "debuggers", HandleFurnaceFuel, "- Shows how long the currently held item would burn in a furnace"); + PM:BindCommand("/sched", "debuggers", HandleSched, "- Schedules a simple countdown using cWorld:ScheduleTask()"); Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers); @@ -955,6 +956,45 @@ end +function HandleSched(a_Split, a_Player) + local World = a_Player:GetWorld() + + -- Schedule a broadcast of a countdown message: + for i = 1, 10 do + World:ScheduleTask(i * 20, + function(a_World) + a_World:BroadcastChat("Countdown: " .. 11 - i) + end + ) + end + + -- Schedule a broadcast of the final message and a note to the originating player + -- Note that we CANNOT us the a_Player in the callback - what if the player disconnected? + -- Therefore we store the player's EntityID + local PlayerID = a_Player:GetUniqueID() + World:ScheduleTask(220, + function(a_World) + a_World:BroadcastChat("Countdown: BOOM") + a_World:DoWithEntityByID(PlayerID, + function(a_Entity) + if (a_Entity:IsPlayer()) then + -- Although unlikely, it is possible that this player is not the originating player + -- However, I leave this as an excercise to you to fix this "bug" + local Player = tolua.cast(a_Entity, "cPlayer") + Player:SendMessage("Countdown finished") + end + end + ) + end + ) + + return true +end + + + + + function HandleRequest_Debuggers(a_Request) local FolderContents = cFile:GetFolderContents("./"); return "

The following objects have been returned by cFile:GetFolderContents():

"; diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 3ebe7b294..2206dd371 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -986,11 +986,10 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S) class cLuaScheduledWorldTask : - public cWorld::cScheduledTask + public cWorld::cTask { public: - cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef, int a_Ticks) : - cScheduledTask(a_Ticks), + cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) : m_Plugin(a_Plugin), m_FnRef(a_FnRef) { @@ -1025,15 +1024,20 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) } // Retrieve the args: - cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, 0); - if (self == NULL) + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber (2) || + !L.CheckParamFunction(3) + ) + { + return 0; + } + cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL); + if (World == NULL) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); } - if (!lua_isfunction(tolua_S, 2)) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1"); - } // Create a reference to the function: int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); @@ -1042,9 +1046,9 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } - int Ticks = (int) tolua_tonumber (tolua_S, 3, 0); + int DelayTicks = (int)tolua_tonumber(tolua_S, 2, 0); - self->ScheduleTask(new cLuaScheduledWorldTask(*Plugin, FnRef, Ticks)); + World->ScheduleTask(DelayTicks, new cLuaScheduledWorldTask(*Plugin, FnRef)); return 0; } diff --git a/src/World.cpp b/src/World.cpp index 6520702c7..5e9f4a38a 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -865,13 +865,17 @@ void cWorld::TickQueuedTasks(void) } // for itr - m_Tasks[] } -void cWorld::TickScheduledTasks() + + + + +void cWorld::TickScheduledTasks(void) { - ScheduledTaskList Tasks; // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks + cScheduledTasks Tasks; { cCSLock Lock(m_CSScheduledTasks); - while (!m_ScheduledTasks.empty() && m_ScheduledTasks.front()->Ticks < m_WorldAge) + while (!m_ScheduledTasks.empty() && (m_ScheduledTasks.front()->m_TargetTick < m_WorldAge)) { Tasks.push_back(m_ScheduledTasks.front()); m_ScheduledTasks.pop_front(); @@ -879,9 +883,9 @@ void cWorld::TickScheduledTasks() } // Execute and delete each task: - for (ScheduledTaskList::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) + for (cScheduledTasks::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) { - (*itr)->Run(*this); + (*itr)->m_Task->Run(*this); delete *itr; } // for itr - m_Tasks[] } @@ -2627,19 +2631,25 @@ void cWorld::QueueTask(cTask * a_Task) m_Tasks.push_back(a_Task); } -void cWorld::ScheduleTask(cScheduledTask * a_Task) + + + + +void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task) { - a_Task->Ticks = a_Task->Ticks + m_WorldAge; + Int64 TargetTick = a_DelayTicks + m_WorldAge; + + // Insert the task into the list of scheduled tasks, ordered by its target tick cCSLock Lock(m_CSScheduledTasks); - for(ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end(); itr++) + for (cScheduledTasks::iterator itr = m_ScheduledTasks.begin(), end = m_ScheduledTasks.end(); itr != end; ++itr) { - if((*itr)->Ticks >= a_Task->Ticks) + if ((*itr)->m_TargetTick >= TargetTick) { - m_ScheduledTasks.insert(itr, a_Task); + m_ScheduledTasks.insert(itr, new cScheduledTask(TargetTick, a_Task)); return; } } - m_ScheduledTasks.push_back(a_Task); + m_ScheduledTasks.push_back(new cScheduledTask(TargetTick, a_Task)); } diff --git a/src/World.h b/src/World.h index 1a7ad0cb1..930d9d421 100644 --- a/src/World.h +++ b/src/World.h @@ -66,7 +66,7 @@ public: // tolua_end - /// A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor + /** A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor */ class cLock : public cCSLock { @@ -74,8 +74,9 @@ public: public: cLock(cWorld & a_World); } ; + - /// A common ancestor for all tasks queued onto the tick thread + /** A common ancestor for all tasks queued onto the tick thread */ class cTask { public: @@ -83,18 +84,8 @@ public: virtual void Run(cWorld & a_World) = 0; } ; - /// A common ancestor for all scheduled tasks queued onto the tick thread - class cScheduledTask - { - public: - cScheduledTask(const int a_Ticks) : Ticks(a_Ticks) {}; - virtual ~cScheduledTask() {}; - virtual void Run(cWorld & a_World) = 0; - int Ticks; - }; - typedef std::vector cTasks; - typedef std::list ScheduledTaskList; + class cTaskSaveAllChunks : public cTask @@ -128,16 +119,16 @@ public: BroadcastTimeUpdate(); } - /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable + /** Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */ eGameMode GetGameMode(void) const { return m_GameMode; } - /// Returns true if the world is in Creative mode + /** Returns true if the world is in Creative mode */ bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); } - /// Returns true if the world is in Survival mode + /** Returns true if the world is in Survival mode */ bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); } - /// Returns true if the world is in Adventure mode + /** Returns true if the world is in Adventure mode */ bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); } bool IsPVPEnabled(void) const { return m_bEnabledPVP; } @@ -147,12 +138,12 @@ public: eDimension GetDimension(void) const { return m_Dimension; } - /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated + /** Returns the world height at the specified coords; waits for the chunk to get loaded / generated */ int GetHeight(int a_BlockX, int a_BlockZ); // tolua_end - /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated + /** 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 // Broadcast respective packets to all clients of the chunk where the event is taking place @@ -187,7 +178,7 @@ public: void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ); void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL); - /// If there is a block entity at the specified coords, sends it to the client specified + /** If there is a block entity at the specified coords, sends it to the client specified */ void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); @@ -221,7 +212,7 @@ public: bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback); - /// Gets the chunk's blocks, only the block types + /** Gets the chunk's blocks, only the block types */ bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes); bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const; @@ -234,13 +225,13 @@ public: void AddPlayer( cPlayer* a_Player ); void RemovePlayer( cPlayer* a_Player ); - /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true - bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - - /// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored - bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << + /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ + bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - /// Finds a player from a partial or complete player name and calls the callback - case-insensitive + /** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored */ + bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << + + /** Finds a player from a partial or complete player name and calls the callback - case-insensitive */ bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action) @@ -248,74 +239,74 @@ public: void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player - /// Adds the entity into its appropriate chunk; takes ownership of the entity ptr + /** Adds the entity into its appropriate chunk; takes ownership of the entity ptr */ void AddEntity(cEntity * a_Entity); bool HasEntity(int a_UniqueID); - /// Removes the entity, the entity ptr ownership is assumed taken by the caller + /** Removes the entity, the entity ptr ownership is assumed taken by the caller */ void RemoveEntity(cEntity * a_Entity); - /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true + /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true + /** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. + /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */ bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Compares clients of two chunks, calls the callback accordingly + /** Compares clients of two chunks, calls the callback accordingly */ void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); - /// Adds client to a chunk, if not already present; returns true if added, false if present + /** Adds client to a chunk, if not already present; returns true if added, false if present */ bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - /// Removes client from the chunk specified + /** Removes client from the chunk specified */ void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - /// Removes the client from all chunks it is present in + /** Removes the client from all chunks it is present in */ void RemoveClientFromChunks(cClientHandle * a_Client); - /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted) + /** Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted) */ void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - /// Removes client from ChunkSender's queue of chunks to be sent + /** Removes client from ChunkSender's queue of chunks to be sent */ void RemoveClientFromChunkSender(cClientHandle * a_Client); - /// Touches the chunk, causing it to be loaded or generated + /** Touches the chunk, causing it to be loaded or generated */ void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - /// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) + /** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */ bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - /// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() + /** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */ void LoadChunks(const cChunkCoordsList & a_Chunks); - /// Marks the chunk as failed-to-load: + /** Marks the chunk as failed-to-load: */ void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() + /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() */ bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp - /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines() + /** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines() */ bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp - /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay! + /** Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay! */ void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true); - /// Regenerate the given chunk: + /** Regenerate the given chunk: */ void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - /// Generates the given chunk, if not already generated + /** Generates the given chunk, if not already generated */ void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - /// Queues a chunk for lighting; a_Callback is called after the chunk is lighted + /** Queues a chunk for lighting; a_Callback is called after the chunk is lighted */ void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL); bool IsChunkLighted(int a_ChunkX, int a_ChunkZ); - /// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully + /** Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully */ bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback); // tolua_begin @@ -366,30 +357,30 @@ public: // tolua_begin - /// Spawns item pickups for each item in the list. May compress pickups if too many entities: + /** Spawns item pickups for each item in the list. May compress pickups if too many entities: */ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false); - /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: + /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false); - /// Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. + /** Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. */ int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta); - /// Spawns an minecart at the given coordinates. + /** Spawns an minecart at the given coordinates. */ int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1); - /// Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. + /** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */ int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward); - /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided + /** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */ void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1); // tolua_end - /// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType + /** Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType */ void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType); - /// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. + /** Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. */ bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure); // tolua_begin @@ -400,10 +391,10 @@ public: double GetSpawnY(void) const { return m_SpawnY; } double GetSpawnZ(void) const { return m_SpawnZ; } - /// Wakes up the simulators for the specified block + /** Wakes up the simulators for the specified block */ void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ); - /// Wakes up the simulators for the specified area of blocks + /** Wakes up the simulators for the specified area of blocks */ void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ); // tolua_end @@ -414,22 +405,22 @@ public: inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; } inline cRedstoneSimulator * GetRedstoneSimulator(void) { return m_RedstoneSimulator; } - /// Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true + /** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */ bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true + /** Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true */ bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true + /** Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true */ bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); - /// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true + /** Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true */ bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback); - /// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true + /** Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true */ bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback); - /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true + /** Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true */ bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp /** Does an explosion with the specified strength at the specified coordinate @@ -447,71 +438,71 @@ public: */ void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export - /// Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found + /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found + /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found + /** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */ bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found + /** Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */ bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found + /** Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */ bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found + /** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */ bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found + /** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */ bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found + /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Exported in ManualBindings.cpp - /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found + /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp - /// a_Player is using block entity at [x, y, z], handle that: + /** a_Player is using block entity at [x, y, z], handle that: */ void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); } // tolua_export - /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback + /** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */ bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback); void GrowTreeImage(const sSetBlockVector & a_Blocks); // tolua_begin - /// Grows a tree at the specified coords, either from a sapling there, or based on the biome + /** Grows a tree at the specified coords, either from a sapling there, or based on the biome */ void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); - /// Grows a tree at the specified coords, based on the sapling meta provided + /** Grows a tree at the specified coords, based on the sapling meta provided */ void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_SaplingMeta); - /// Grows a tree at the specified coords, based on the biome in the place + /** Grows a tree at the specified coords, based on the biome in the place */ void GrowTreeByBiome (int a_BlockX, int a_BlockY, int a_BlockZ); - /// Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini + /** Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini */ bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false); - /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config + /** Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config */ void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - /// Grows a melon or a pumpkin next to the block specified (assumed to be the stem) + /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem) */ void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); - /// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config + /** Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config */ void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - /// Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value + /** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value */ int GetBiomeAt(int a_BlockX, int a_BlockZ); - /// Returns the name of the world + /** Returns the name of the world */ const AString & GetName(void) const { return m_WorldName; } - /// Returns the name of the world.ini file used by this world + /** Returns the name of the world.ini file used by this world */ const AString & GetIniFileName(void) const {return m_IniFileName; } // tolua_end @@ -543,22 +534,23 @@ public: if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--; } - /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead + /** Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead */ void SaveAllChunks(void); - /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources + /** Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources */ void QueueSaveAllChunks(void); // tolua_export - /// Queues a task onto the tick thread. The task object will be deleted once the task is finished + /** Queues a task onto the tick thread. The task object will be deleted once the task is finished */ void QueueTask(cTask * a_Task); // Exported in ManualBindings.cpp - // Queues a task onto the tick thread. The task object will be deleted once the task is finished - void ScheduleTask(cScheduledTask * a_Task); + /** Queues a task onto the tick thread, with the specified delay. + The task object will be deleted once the task is finished */ + void ScheduleTask(int a_DelayTicks, cTask * a_Task); - /// Returns the number of chunks loaded + /** Returns the number of chunks loaded */ int GetNumChunks() const; // tolua_export - /// Returns the number of chunks loaded and dirty, and in the lighting queue + /** Returns the number of chunks loaded and dirty, and in the lighting queue */ void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue); // Various queues length queries (cannot be const, they lock their CS): @@ -569,13 +561,13 @@ public: void InitializeSpawn(void); - /// Starts threads that belong to this world + /** Starts threads that belong to this world */ void Start(void); - /// Stops threads that belong to this world (part of deinit) + /** Stops threads that belong to this world (part of deinit) */ void Stop(void); - /// Processes the blocks queued for ticking with a delay (m_BlockTickQueue[]) + /** Processes the blocks queued for ticking with a delay (m_BlockTickQueue[]) */ void TickQueuedBlocks(void); struct BlockTickQueueItem @@ -586,27 +578,27 @@ public: int TicksToWait; }; - /// Queues the block to be ticked after the specified number of game ticks + /** Queues the block to be ticked after the specified number of game ticks */ void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, int a_TicksToWait); // tolua_export // tolua_begin - /// Casts a thunderbolt at the specified coords + /** Casts a thunderbolt at the specified coords */ void CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ); - /// Sets the specified weather; resets weather interval; asks and notifies plugins of the change + /** Sets the specified weather; resets weather interval; asks and notifies plugins of the change */ void SetWeather (eWeather a_NewWeather); - /// Forces a weather change in the next game tick + /** Forces a weather change in the next game tick */ void ChangeWeather (void); - /// Returns the current weather. Instead of comparing values directly to the weather constants, use IsWeatherXXX() functions, if possible + /** Returns the current weather. Instead of comparing values directly to the weather constants, use IsWeatherXXX() functions, if possible */ eWeather GetWeather (void) const { return m_Weather; }; bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } bool IsWeatherRain (void) const { return (m_Weather == wRain); } bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } - /// Returns true if the current weather has any precipitation - rain or storm + /** Returns true if the current weather has any precipitation - rain or storm */ bool IsWeatherWet (void) const { return (m_Weather != wSunny); } // tolua_end @@ -615,7 +607,7 @@ public: cWorldStorage & GetStorage (void) { return m_Storage; } cChunkMap * GetChunkMap (void) { return m_ChunkMap; } - /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call + /** Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call */ void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export @@ -623,20 +615,20 @@ public: bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise + /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */ int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export int SpawnMobFinalize(cMonster* a_Monster); - /// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise + /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export - /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! + /** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */ int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); } - /// Appends all usernames starting with a_Text (case-insensitive) into Results + /** Appends all usernames starting with a_Text (case-insensitive) into Results */ void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results); - /// Get the current darkness level based on the time + /** Get the current darkness level based on the time */ NIBBLETYPE GetSkyDarkness() { return m_SkyDarkness; } private: @@ -679,18 +671,41 @@ private: } ; + /** A container for tasks that have been scheduled for a specific game tick */ + class cScheduledTask + { + public: + Int64 m_TargetTick; + cTask * m_Task; + + /** Creates a new scheduled task; takes ownership of the task object passed to it. */ + cScheduledTask(Int64 a_TargetTick, cTask * a_Task) : + m_TargetTick(a_TargetTick), + m_Task(a_Task) + { + } + + virtual ~cScheduledTask() + { + delete m_Task; + } + }; + + typedef std::list cScheduledTasks; + + AString m_WorldName; AString m_IniFileName; - /// Name of the storage schema used to load and save chunks + /** Name of the storage schema used to load and save chunks */ AString m_StorageSchema; int m_StorageCompressionFactor; - /// The dimension of the world, used by the client to provide correct lighting scheme + /** The dimension of the world, used by the client to provide correct lighting scheme */ eDimension m_Dimension; - /// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe) + /** This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe) */ MTRand m_TickRand; bool m_IsSpawnExplicitlySet; @@ -765,29 +780,30 @@ private: cLightingThread m_Lighting; cTickThread m_TickThread; - /// Guards the m_Tasks + /** Guards the m_Tasks */ cCriticalSection m_CSTasks; - /// Guards the m_ScheduledTasks - cCriticalSection m_CSScheduledTasks; - - /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks + /** Tasks that have been queued onto the tick thread; guarded by m_CSTasks */ cTasks m_Tasks; - /// Tasks that have been queued to be executed on the tick thread at some number of ticks in - /// the future; guarded by m_CSScheduledTasks - ScheduledTaskList m_ScheduledTasks; + /** Guards the m_ScheduledTasks */ + cCriticalSection m_CSScheduledTasks; - /// Guards m_Clients + /** Tasks that have been queued to be executed on the tick thread at target tick in the future. + Ordered by increasing m_TargetTick. + Guarded by m_CSScheduledTasks */ + cScheduledTasks m_ScheduledTasks; + + /** Guards m_Clients */ cCriticalSection m_CSClients; - /// List of clients in this world, these will be ticked by this world + /** List of clients in this world, these will be ticked by this world */ cClientHandleList m_Clients; - /// Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them + /** Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them */ cClientHandleList m_ClientsToRemove; - /// Clients that are scheduled for adding, waiting for TickClients to add them + /** Clients that are scheduled for adding, waiting for TickClients to add them */ cClientHandleList m_ClientsToAdd; @@ -796,27 +812,27 @@ private: void Tick(float a_Dt, int a_LastTickDurationMSec); - /// Handles the weather in each tick + /** Handles the weather in each tick */ void TickWeather(float a_Dt); - /// Handles the mob spawning/moving/destroying each tick + /** Handles the mob spawning/moving/destroying each tick */ void TickMobs(float a_Dt); - /// Executes all tasks queued onto the tick thread + /** Executes all tasks queued onto the tick thread */ void TickQueuedTasks(void); - /// Executes all tasks queued onto the tick thread + /** Executes all tasks queued onto the tick thread */ void TickScheduledTasks(void); - /// Ticks all clients that are in this world + /** Ticks all clients that are in this world */ void TickClients(float a_Dt); void UpdateSkyDarkness(void); - /// Generates a random spawnpoint on solid land by walking chunks and finding their biomes + /** Generates a random spawnpoint on solid land by walking chunks and finding their biomes */ void GenerateRandomSpawn(void); - /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) + /** Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) */ cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock); }; // tolua_export