12-01-2015, 07:54 AM
So I'm currently writing a portals plugin. Right now, it's only going to be for BungeeCord, but eventually I might make it for other things (like multiworld, in world, etc). I've already figure out how I can define areas (either using a worldedit API call or using a special stick to get the two corners), so that's not the problem. The thing I want input on is how best to handle checking if a player is in a portal. There's a number of methods, but it would have to use the onPlayerMoved(ing? one of those) hook, correct? As such, I want to do as minimal a processing as possible. I've come up with a few simple ideas, but each one has downsides. There are also a few other options I've come up with (such as portals being made of specific blocks so I can check for blocktype or air/portal block beneath the player and return false if they don't match), but I'd rather not use those methods. So, here are my ideas:
Method 1:
Nested for's every ... no.
Method 2:
Store all portals in, say, g_Portals, in the format
Pro: Handles a small number of any size portals extremely well
Con: A large number of portals/players could cause serious server lag.
Method 3:
On startup, the plugin takes an input table of the form from method 2 (probably actually sqlite information, unless I get lazy again and just use file storage) and produces a table of all coordinates in the form
g_PortalBlocks[x_value][y_value][z_value] = "portal_name"
and then references another table (say, g_Portals) like g_Portals["portal_name"] = {..information here..} so that the code would like like this
Pros: Incredibly fast, no matter how many people/portals there are.
Cons: A large number of portals and/or large portals could cause massive memory usage.
Method 4:
Using a cCuboid constructed at startup (likely as an element of the g_Portals table at key "portal_name") instead of a custom object in method 2, and therefore using IsInside instead of the chained ands.
Pro/Con: Based entirely on how this is different from method 2 in terms of speed/memory usage, and possibly other things. Can't say I know this.
Method 5:
Use Vector3i for a kind of combination of method 2 and 3. Pro: can't really think of any. Con: Has the downsides of BOTH method 2 and 3 so... probably not.
Method 6:
???
I'm currently leaning towards method 3 as I think that the bad situation in method 3 (extremely large (numbers of) portals) is significantly less likely to happen then the bad situation in method 2/4 (large number of players/portals), and can also be somewhat solved by limiting the size of portals. Also because method 3 is a memory issue (that I believe would have to go to extreme measures to cause noticeable impact) whereas method 2 is a "stops the server really frequently" issue. However, I'd love to know any methods that someone else suggests (ex: a good way to use cCuboid or even Vector3(d/f/i) in a way other than listed above).
Method 1:
Nested for's every ... no.
Method 2:
Store all portals in, say, g_Portals, in the format
g_Portals = { name1: { xmin = 0 xman = 1 ymin = 10 ymax = 100 zmin = 10 zmax = 100 information = { -- information goes here } }, .... } function checkPortal(x,y,z) for k,v in pairs(g_Portals) do if v.xmin <= x and v.xmax >= x and ... and v.zmax <= z then return v.information end end return false end
Pro: Handles a small number of any size portals extremely well
Con: A large number of portals/players could cause serious server lag.
Method 3:
On startup, the plugin takes an input table of the form from method 2 (probably actually sqlite information, unless I get lazy again and just use file storage) and produces a table of all coordinates in the form
g_PortalBlocks[x_value][y_value][z_value] = "portal_name"
and then references another table (say, g_Portals) like g_Portals["portal_name"] = {..information here..} so that the code would like like this
function checkPortal(x,y,z) return g_Portals[g_PortalBlocks[x][y][z]] endThen you could just use an if to check if the return is nil, and if not, use the information to teleport. This plugin would use the integer location type for this, so that decimals don't mess everything up.
Pros: Incredibly fast, no matter how many people/portals there are.
Cons: A large number of portals and/or large portals could cause massive memory usage.
Method 4:
Using a cCuboid constructed at startup (likely as an element of the g_Portals table at key "portal_name") instead of a custom object in method 2, and therefore using IsInside instead of the chained ands.
Pro/Con: Based entirely on how this is different from method 2 in terms of speed/memory usage, and possibly other things. Can't say I know this.
Method 5:
Use Vector3i for a kind of combination of method 2 and 3. Pro: can't really think of any. Con: Has the downsides of BOTH method 2 and 3 so... probably not.
Method 6:
???
I'm currently leaning towards method 3 as I think that the bad situation in method 3 (extremely large (numbers of) portals) is significantly less likely to happen then the bad situation in method 2/4 (large number of players/portals), and can also be somewhat solved by limiting the size of portals. Also because method 3 is a memory issue (that I believe would have to go to extreme measures to cause noticeable impact) whereas method 2 is a "stops the server really frequently" issue. However, I'd love to know any methods that someone else suggests (ex: a good way to use cCuboid or even Vector3(d/f/i) in a way other than listed above).