Is there a cheaper more efficient way to check the player's location?

I’ve been working with some code to check if the player is in a specified location and if they are in said place, music will begin playing using sound.PlayURL() and will only fire once and when they leave the sound will fade out (I have yet to figure that out)
However, I cannot find a cheap way to check the player’s location without going through for loops and causing alot of server-side lag.
Is there any other alternative I could check the player’s location without having to go through the entire table?



locations = {
	{ "Funature Store", Vector(-882.253540, -1649.807495, 0), Vector(-274.743256, -1288.234375, 134) },
	{ "Electronics Store", Vector(58.338486, -1769.410767, -118.918518), Vector(-261.801636, -1286.127319, -5.749599) },
	{ "Small Cafe", Vector(58.338486, -1769.410767, -118.918518), Vector(319.372589, -1285.285889, -5.375816) },
}

hook.Add( "Move", "CheckPlayerPosition", function( ply )
	local function CheckPosition( pos )
		local i = 1
		while i != table.GetLastKey( locations ) do
			if pos:WithinAABox( area[2], area[3] ) then
				return area[1]
				break
			end
		end
	end

	local CurrentArea = CheckPosition( pos )

	if CurrentArea != nil and ply:GetNWString( "CurrentLocation" ) != CurrentArea then
		sound.PlayURL( "http://media.soundcloud.com/stream/DiRLSLR42BF4.mp3", "mono", function() end ) -- Placeholder Song
		ply:SetNWString( "CurrentLocation", CurrentArea )
	end
end )


You sure it’s that script causing serversided lag? sound.PlayURL is clientsided. That code shouldn’t even work serverside.

If you move it to clientside, you can just move it to a timer that checks every x seconds. I have a similar system for a gamemode I’m working on.



function CheckPos(ply)
    local loc
    for k,v in pairs(locations) do
        if ply:GetPos():WithinAABox(v[2], v[3]) then
            return loc
        end
    end
end

timer.Create("MusicCheck", 3, 0, function()
    local loc = CheckPos(LocalPlayer())
    
    if loc then
        sound.PlayURL("http://media.soundcloud.com/stream/DiRLSLR42BF4.mp3", "mono", function() end) -- Placeholder Song
        LocalPlayer():SetNWString("CurrentLocation", loc)
    end
end)


Edit: Granted, the SetNWString bit is useless since it doesn’t network it client > server.

you could check if the player’s distance to the center of the box is within a certain radius so that you don’t have to call withinaabox because it sounds expensive
if you do that, use disttosqr because it’s cheaper than distance

The lower part was made quickly, what I’m going for is simply a player tracker the scoreboard. However, I was wondering if this system would be too wasteful as I will be filling this table with over 10 locations and having the code loop multiple times seems extremely wasteful and inefficient. I was wondering if there was a way to optimize the code a bit to not use so many resources. Every time a player moves on the server as there will likely be more than 20 players on spontaneously moving making this a very demanding task to perform.

also, since calling functions is automatically a little more expensive than just running code, you could do what I assume withinaabox is doing and just check if the player’s pos is > v[1] and < v[2] (not literally, you’d have to check x y and z)

Couldn’t you make an invisible box-shaped entity, set SetTrigger to true and use ENT:StartTouch to register when a player enters the areas?

How would you go upon spawning a trigger_multiple entity?
I know that you would use ents.Create() but how would you pinpoint what the box dimensions are vector-wise?

You can’t AFAIK, you’d better make your own entity, set its collision bounds (or whatever is used in this case) and use ENT:StartTouch.

-snip- solution was already posted, didn’t bother reading whole thread

On my CWHL2RP system, we used to use map triggers that checked on the Think hook to see if you were inside. I ended up later completely porting it to a LUA entity that increased performance by calling only once when entering and exiting-- which improved performance a butt-ton.

Somewhere in your code (you’ll need to get rid of the function):



function PLUGIN:LoadAirAreas()
	local triggerzones = {
	"safezone_fotochange",
	"safezone_nexus",
	"safezone_rations",
	"safezone_terminalhotel",
	"safezone_hospital",
	"safezone_train",
	"safezone_factory1",
	"safezone_grotto",
	"safezone_constructionshop",
	"safezone_theater",
	"safezone_shop1",
	"safezone_baltic",
	"safezone_lolwebulbase",
	"safezone_oldapartments",
	"safezone_garage",
	"safezone_canalroom1",
	"safezone_canalroom2",
	"safezone_canalroom3",
	"safezone_quarry",
	"safezone_ubc",
	"safezone_shop2",
	"safezone_factory2",
	"safezone_roofcafe",
	"safezone_roofapartments",
	"safezone_shop3",
	"safezone_cpoutpost",
	"safezone_garbage",
	"safezone_diordna",
	"safezone_metropol"
	}
	for _, ent in ipairs(ents.FindByClass( "trigger_multiple" )) do
		if table.HasValue(triggerzones, ent:GetName()) then
			local novaboxisepic = ents.Create("safezones");
			local entity = novaboxisepic:SpawnFunction(ent:OBBMins(), ent:OBBMaxs(), ent:GetPos(), ent:GetAngles())
			novaboxisepic:Remove()
		end;
	end;
end;


What I did was get a list of /triggers/ that were built into the map and had their positions grabbed, you can either do the same thing or just as easily grab the position/size data from a table.

init.lua



ENT.Type = "brush"
ENT.Spawnable = false -- Nope
ENT.AdminSpawnable = false -- We want to spawn and modify within lua only and not be controlled outside of the files.

-- Called when the entity is spawned.
function ENT:SpawnFunction(minb, maxb, pos, ang)
    local entity = ents.Create("safezones");
    entity:Spawn();
	entity:SetCollisionBoundsWS(minb, maxb)
	entity:SetPos(pos)
end

-- Called when the entity inits.
function ENT:Initialize()
	self:SetSolid( SOLID_BBOX ) -- Not Solid
    self:SetTrigger(true) -- So self is editable with lua.
end

-- Called when the entity starts touching something.
function ENT:StartTouch( entity )
	
	if ( !entity:IsValid() ) then return end -- Check to make sure the entity is valid.
	
	if ( !entity:IsPlayer() ) then return end -- Check if a player
	
	AirExtractor:SetSafeAir(entity, true)

end

-- Called when the entity stops touching something.
function ENT:EndTouch( entity )

	if ( !entity:IsValid() ) then return end -- Check to make sure the entity is valid.

	if ( !entity:IsPlayer() ) then return end -- Check if a player
	
	AirExtractor:SetSafeAir(entity, false)
	
end


Replace:


AirExtractor:SetSafeAir(entity, false)

With your whatever.