ProtectionAreas: Implemented reloading areas when a player moves

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1575 0a769ca7-a7f5-676a-18bf-c427514a06d6
master
madmaxoft@gmail.com 2013-06-10 07:21:52 +00:00
parent ed06d13b5c
commit 2adf62e22e
4 changed files with 78 additions and 13 deletions

View File

@ -6,10 +6,12 @@
--- Registers all the hooks that the plugin needs to know about
function InitializeHooks(a_Plugin)
local PlgMgr = cRoot:Get():GetPluginManager();
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_DISCONNECT);
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_PLAYER_LEFT_CLICK);
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_PLAYER_MOVING);
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_PLAYER_RIGHT_CLICK);
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_PLAYER_SPAWNED);
end
@ -18,6 +20,7 @@ end
--- Called by MCS when a player's connectino is lost - either they disconnected or timed out
function OnDisconnect(a_Player, a_Reason)
-- Remove the player's cProtectionArea object
-- TODO: What if there are two players with the same name? need to check
@ -33,6 +36,7 @@ end;
--- Called by MCS whenever a player enters a world (is spawned)
function OnPlayerSpawned(a_Player)
-- Create a new cPlayerAreas object for this player
if (g_PlayerAreas[a_Player:GetUniqueID()] == nil) then
@ -46,6 +50,29 @@ end
--- Called by MCS whenever a player is moving (at most once every tick)
function OnPlayerMoving(a_Player)
local PlayerID = a_Player:GetUniqueID();
-- If for some reason we don't have a cPlayerAreas object for this player, load it up
local PlayerAreas = g_PlayerAreas[PlayerID];
if (PlayerAreas == nil) then
LoadPlayerAreas(a_Player);
return false;
end;
-- If the player is outside their areas' safe space, reload
if (not(PlayerAreas:IsInSafe(a_Player:GetPosX(), a_Player:GetPosZ()))) then
LoadPlayerAreas(a_Player);
end
return false;
end
--- Called by MCS when a player left-clicks
function OnPlayerLeftClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status)
-- If the player has lclked with the wand; regardless of their permissions, let's set the coords:
if (cConfig:IsWand(a_Player:GetEquippedItem())) then
@ -65,7 +92,8 @@ function OnPlayerLeftClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
-- Check the player areas to see whether to disable this action
local Areas = g_PlayerAreas[a_Player:GetUniqueID()];
if not(Areas:CanInteractWithBlock(a_BlockX, a_BlockY, a_BlockZ)) then
if not(Areas:CanInteractWithBlock(a_BlockX, a_BlockZ)) then
a_Player:SendMessage("You are not allowed to dig here!");
return true;
end
@ -77,9 +105,9 @@ end
--- Called by MCS when a player right-clicks
function OnPlayerRightClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_Status)
-- If the player has rclked with the wand; regardless of their permissions, let's set the coords
if (cConfig:IsWand(a_Player:GetEquippedItem())) then
-- BlockFace < 0 means "use item", for which the coords are not given by the client
if (a_BlockFace < 0) then
return true;
@ -88,6 +116,8 @@ function OnPlayerRightClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
-- Convert the clicked coords into the block space
a_BlockX, a_BlockY, a_BlockZ = AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-- If the player has rclked with the wand; regardless of their permissions, let's set the coords
if (cConfig:IsWand(a_Player:GetEquippedItem())) then
-- Set the coords in the CommandState
GetCommandStateForPlayer(a_Player):SetCoords2(a_BlockX, a_BlockZ);
a_Player:SendMessage("Coords2 set as {" .. a_BlockX .. ", " .. a_BlockZ .."}.");
@ -97,6 +127,7 @@ function OnPlayerRightClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
-- Check the player areas to see whether to disable this action
local Areas = g_PlayerAreas[a_Player:GetUniqueID()];
if not(Areas:CanInteractWithBlock(a_BlockX, a_BlockZ)) then
a_Player:SendMessage("You are not allowed to build here!");
return true;
end

View File

@ -9,7 +9,8 @@ The code can then ask each object, whether the player can interact with a certai
A player can interact with a block if either one of these is true:
1, There are no areas covering the block
2, There is at least one area covering the block with IsAllowed set to true
The OOP class implementation follows the PiL 16.1
The object also has a m_SafeCuboid object that specified the area within which the player may move
without the PlayerAreas needing a re-query.
Also, a global table g_PlayerAreas is the actual map of PlayerID -> cPlayerAreas
--]]
@ -25,10 +26,16 @@ g_PlayerAreas = {};
function cPlayerAreas:new(obj)
obj = obj or {};
function cPlayerAreas:new(a_SafeMinX, a_SafeMinZ, a_SafeMaxX, a_SafeMaxZ)
assert(a_SafeMinX);
assert(a_SafeMinZ);
assert(a_SafeMaxX);
assert(a_SafeMaxZ);
local obj = {};
setmetatable(obj, self);
self.__index = self;
self.m_SafeCuboid = cCuboid(a_SafeMinX, 0, a_SafeMinZ, a_SafeMaxX, 255, a_SafeMaxZ);
return obj;
end
@ -46,6 +53,8 @@ end
--- returns true if the player owning this object can interact with the specified block
function cPlayerAreas:CanInteractWithBlock(a_BlockX, a_BlockZ)
assert(self);
-- iterate through all the stored areas:
local IsInsideAnyArea = false;
for idx, Area in ipairs(self) do
@ -76,6 +85,8 @@ end
-- a_Callback has a signature: function(a_Cuboid, a_IsAllowed)
-- Returns true if all areas have been enumerated, false if the callback has aborted by returning true
function cPlayerAreas:ForEachArea(a_Callback)
assert(self);
for idx, Area in ipairs(self) do
if (a_Callback(Area.m_Cuboid, Area.m_IsAllowed)) then
return false;
@ -87,3 +98,13 @@ end
--- Returns true if the player is withing the safe cuboid (no need to re-query the areas)
function cPlayerAreas:IsInSafe(a_BlockX, a_BlockZ)
assert(self);
return self.m_SafeCuboid:IsInside(a_BlockX, 0, a_BlockZ);
end

View File

@ -12,6 +12,9 @@ PluginPrefix = "ProtectionAreas: ";
--- Bounds for the area loading. Areas less this far in any direction from the player will be loaded into cPlayerAreas
g_AreaBounds = 48;
--- If a player moves this close to the PlayerAreas bounds, the PlayerAreas will be re-queried
g_AreaSafeEdge = 12;

View File

@ -192,7 +192,17 @@ function cStorage:LoadPlayerAreas(a_PlayerName, a_PlayerX, a_PlayerZ, a_WorldNam
local BoundsMinZ = a_PlayerZ - g_AreaBounds;
local BoundsMaxZ = a_PlayerZ + g_AreaBounds;
local res = cPlayerAreas:new();
local res = cPlayerAreas:new(
BoundsMinX + g_AreaSafeEdge, BoundsMinZ + g_AreaSafeEdge,
BoundsMaxX - g_AreaSafeEdge, BoundsMaxZ - g_AreaSafeEdge
);
--[[
LOG("Loading protection areas for player " .. a_PlayerName .. " centered around {" .. a_PlayerX .. ", " .. a_PlayerZ ..
"}, bounds are {" .. BoundsMinX .. ", " .. BoundsMinZ .. "} - {" ..
BoundsMaxX .. ", " .. BoundsMaxZ .. "}"
);
--]]
-- Load the areas from the DB, based on the player's location
local sql =