summaryrefslogtreecommitdiffstats
path: root/MCServer/Plugins/ProtectionAreas/PlayerAreas.lua
blob: 4ff50d8ad342943f49e35ce04329eff83c071e7e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

-- PlayerAreas.lua
-- Implements the cPlayerAreas class representing the per-player area storage object

--[[
Each player instance is expected to have a separate object of type cPlayerAreas.
Each object has an array of {cuboid, IsAllowed} tables, one for each area that is "within reach"
The code can then ask each object, whether the player can interact with a certain block or not.
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 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
--]]




cPlayerAreas = {};

g_PlayerAreas = {};





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




-- Adds a new cuboid to the area list, where the player is either allowed or not, depending on the IsAllowed param
function cPlayerAreas:AddArea(a_Cuboid, a_IsAllowed)
	table.insert(self, {m_Cuboid = a_Cuboid, m_IsAllowed = a_IsAllowed});
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
		if (Area.m_Cuboid:IsInside(a_BlockX, 1, a_BlockZ)) then  -- We don't care about Y coords, so use a dummy value
			if (Area.m_IsAllowed) then
				return true;
			end
			-- The coords are inside a cuboid for which the player doesn't have access, take a note of it
			IsInsideAnyArea = true;
		end
	end
	
	if (IsInsideAnyArea) then
		-- The specified coords are inside at least one area, but none of them allow the player to interact
		return false;
	end
	
	-- The coords are not inside any area
	-- TODO: Have a config saying whether a player can build in the non-areated space or not
	return true;
end





--- Calls the specified callback for each area contained within
-- 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;
		end
	end
	return true;
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