07-02-2012, 07:47 PM
batekman, welcome to the forums. You seem to have a good grasp of Lua if you managed to spot how things are done
Your change probably works okay most of the time, but there's a potential for it to crash the server:
The point of ForEachPlayer() callback mechanism is to force Lua plugins not to handle cPlayer instances anywhere else than in the callback. Imagine this situation:
Your plugin enumerates all players in the world (getPlayerByName() function). But just as this function is about to return the player object, another thread detects that the player has just disconnected, and removes the player from the world. Now Lua has an invalid cPlayer object, but doesn't know it, and as soon as the plugin tries to call a method on this object, the server crashes.
The Correct Way to handle this is to write a small handler function for each action that should be done with the found player, for example:
(note that I didn't try this code out, it's possibly slightly syntactically wrong, it's only to illustrate the approach)
I think I'll add a cWorld:DoWithPlayer(PlayerName, Callback) function later, that would call the callback only for the player of the specified name, so that the callback function can really do only the core minimum that it needs to do. Probably later
Your change probably works okay most of the time, but there's a potential for it to crash the server:
The point of ForEachPlayer() callback mechanism is to force Lua plugins not to handle cPlayer instances anywhere else than in the callback. Imagine this situation:
Your plugin enumerates all players in the world (getPlayerByName() function). But just as this function is about to return the player object, another thread detects that the player has just disconnected, and removes the player from the world. Now Lua has an invalid cPlayer object, but doesn't know it, and as soon as the plugin tries to call a method on this object, the server crashes.
The Correct Way to handle this is to write a small handler function for each action that should be done with the found player, for example:
Code:
function HandleKill(Split, InitiatorPlayer)
-- InitiatorPlayer is valid throughout this function, even within the local function KillSpecificPlayer()
local World = cRoot:Get():GetDefaultWorld()
local HasFound = false
local PlayerName = Split[2]
local KillSpecificPlayer = function(Player)
-- Player is valid only within this callback, it cannot be saved and later used outside of this function!
if (Player:GetName() == PlayerName) then
Player:TakeDamage(100, InitiatorPlayer)
HasFound = true
return true
end
end
World:ForEachPlayer(KillSpecificPlayer)
if (!HasFound) then
InitiatorPlayer:SendMessage(cChatColor.Green .. "Could not find player " .. Split[2])
end
end
I think I'll add a cWorld:DoWithPlayer(PlayerName, Callback) function later, that would call the callback only for the player of the specified name, so that the callback function can really do only the core minimum that it needs to do. Probably later