Jump to content

Using server-side table on client-side.


srslyyyy

Recommended Posts

  • Scripting Moderators

Hey. I was doing some stuff with tables, and i encountered a problem.

So, i have a table with cache data of vehicles, on server-side. I need to change some values, when vehicle got damaged, however i can't use this table on client-side or within onVehicleDamage because there's not attacker parameter, and without it i can't get some additional data.

Looking for workarounds or a solution, - maybe create custom event which will be triggered from client (onClientVehicleDamage) -> server (custom function), but i think so it will decrease performance a lot (triggering on every damage of car done by player), or there's a easier way to get this table up-to-date on client-side, without decreasing performance.

Link to comment
  • Scripting Moderators
39 minutes ago, IIYAMA said:

@majqq

The answer to that depends for 95% on what your endpoint needs. Enough context is essential for coding with responsibility.

 

Well i need to change some data which is server-sided, using client-side event, onClientVehicleDamage.

+ The data on server-side in table, should be updated when player damage a vehicle. (this should be synced for all the players)

Edited by majqq
Link to comment
  • Moderators
57 minutes ago, majqq said:

Well i need to change some data which is server-sided, using client-side event, onClientVehicleDamage.

+ The data on server-side in table, should be updated when player damage a vehicle. (this should be synced for all the players)

 

58 minutes ago, majqq said:

 (this should be synced for all the players)

Oke,

 

Is there more to it? Because this is not enough to pick the right method.

 

For example:

  • Response time?
  • Delay in between?
  • Network bandwidth limit?
  • Parameters?
  • Is it used for visuals only or has it also influence on gameplay directly?
  • Which players do need to receive this information immediately? Which ones later? (Which ones not? > Players that join later or that are far away.)

 

 

  • Thanks 1
Link to comment
  • Scripting Moderators
1 hour ago, aka Blue said:

¿Why you don't make the table shared and manipule it with shared functions? I think it should work.

-- shared
vehiclesCacheData = {

	armorPoints = {},

}

-- server
-- checking data, returns good values.
addCommandHandler("data", function(plr, command)
	local vehicle = getPedOccupiedVehicle(plr)
	if not vehicle then outputChatBox("You need to be in vehicle to get data.", plr) return end
	local parent = getElementData(vehicle, "core:parent")
	if parent and vehicle then
		outputChatBox("Data [1]: "..vehiclesCacheData.armorPoints[parent], plr)
		--outputDebugString("Parent: "..tostring(parent))
	end
end)

-- adding data, somewhere in function
vehiclesCacheData.armorPoints[carCol] = 17 * 100

-- client
-- checking data, returns error or nil.
addCommandHandler("data2", function(plr, command)
		local veh = getPedOccupiedVehicle(getLocalPlayer())
		local parent = getElementData(veh, "core:parent")
		outputChatBox(vehiclesCacheData[parent].armorPoints) -- this will show error - attempt to index field '?' (a nil value)
    	--outputChatBox(vehiclesCacheData.armorPoints[parent]) -- this will show nil
end)

 

I tried, it doesn't wanna work, seems like server/client have separate "shared" tables.

54 minutes ago, IIYAMA said:

 

Oke,

 

Is there more to it? Because this is not enough to pick the right method.

 

For example:

  • Response time?
  • Delay in between?
  • Network bandwidth limit?
  • Parameters?
  • Is it used for visuals only or has it also influence on gameplay directly?
  • Which players do need to receive this information immediately? Which ones later? (Which ones not? > Players that join later or that are far away.)

 

 

 

Well, i decided to switch from using elementData to tables, everything should be okay, i wouldn't need to write this topic if just onVehicleDamage would have attacker parameter.

So:

- Efficient, at all, i had some problems with elementData, i'm sure that this thing was responsible for jumping bars of "vehicle armor", but that's by the way.

- Less what can be, but i still should care for performance at all.

- I can't you answer about it, no clue.

- What parameters you mean?

- It's one of the important things, not a visual thing only.

- What will be best solution for it? To make it works fast, and efficiently. It shouldn't sync for players that aren't logged in, only for players in game.

Link to comment
  • Moderators
2 hours ago, majqq said:

 

 

 

Well, i decided to switch from using elementData to tables, everything should be okay, i wouldn't need to write this topic if just onVehicleDamage would have attacker parameter.

So:

- Efficient, at all, i had some problems with elementData, i'm sure that this thing was responsible for jumping bars of "vehicle armor", but that's by the way.

- Less what can be, but i still should care for performance at all.

- I can't you answer about it, no clue.

- What parameters you mean?

- It's one of the important things, not a visual thing only.

- What will be best solution for it? To make it works fast, and efficiently. It shouldn't sync for players that aren't logged in, only for players in game.

 

- With parameters I mean the arguments you want to use there.

- There are no shared tables.

 

 

I recommend to first try to use the clean way.

  • Sync with triggerEvents, so that you do not destroy other players their network usage directly. (of course this can still happen)
  • Buffer up to at least 200ms.
  • Check if latent events are fast enough for your target group. If your players have bad internet, then it might be possible that the information never gets send... Latent events will only send information when the network isn't blocked. This means that position and orientation of players should be more accurate while sending information.

 

Element data usage will increase when the player count increases, so test it before you use that type instead.

 

Untested code

local damageToSync = {}
local syncVehicleDamageTimer
local function syncVehicleDamage ()
	syncVehicleDamageTimer = nil
	
--  -- -- -- -- -- -- -- -- -- -- -- -- -- --		
	triggerServerEvent("syncVehicleDamage", resourceRoot, damageToSync)
--	-- or -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
	triggerLatentServerEvent("syncVehicleDamage", resourceRoot, damageToSync) -- It will improve the gameplay. >>> BUT this will work ONLY fine if your target players have fast internet. 
--  -- -- -- -- -- -- -- -- -- -- -- -- -- --	

	damageToSync = {} -- reset table
end
	
addEventHandler("onClientVehicleDamage", root, 
function (attacker, weapon, loss)
	if isElementSyncer(source) and attacker and getElementType(attacker) == "player" and loss > 0 then

		-- register vehicle 
		local vehicleDamageTable = damageToSync[source]
		if not vehicleDamageTable then
			vehicleDamageTable = {}
			damageToSync[source] = vehicleDamageTable
		end
		
		-- register attacker + loss of vehicle
		vehicleDamageTable[attacker] = (vehicleDamageTable[attacker] or 0) + loss
		
		-- start sync delay
		if not syncVehicleDamageTimer then
			syncVehicleDamageTimer = setTimer(syncVehicleDamage, 200, 1)
		end
	end
end)

 

The table structure.

--[[

-- table structure --

local damageToSync = {	
	[vehicle] = {
		[attacker] = loss,
		[attacker] = loss
	}
	[vehicle] = {
		[attacker] = loss,
		[attacker] = loss
	}
}
]]

 

  • Thanks 1
Link to comment
  • Scripting Moderators
38 minutes ago, IIYAMA said:

 

- With parameters I mean the arguments you want to use there.

- There are no shared tables.

 

 

I recommend to first try to use the clean way.

  • Sync with triggerEvents, so that you do not destroy other players their network usage directly. (of course this can still happen)
  • Buffer up to at least 200ms.
  • Check if latent events are fast enough for your target group. If your players have bad internet, then it might be possible that the information never gets send... Latent events will only send information when the network isn't blocked. This means that position and orientation of players should be more accurate while sending information.

 

Element data usage will increase when the player count increases, so test it before you use that type instead.

 

Untested code


local damageToSync = {}
local syncVehicleDamageTimer
local function syncVehicleDamage ()
	syncVehicleDamageTimer = nil
	
--  -- -- -- -- -- -- -- -- -- -- -- -- -- --		
	triggerServerEvent("syncVehicleDamage", resourceRoot, damageToSync)
--	-- or -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
	triggerLatentServerEvent("syncVehicleDamage", resourceRoot, damageToSync) -- It will improve the gameplay. >>> BUT this will work ONLY fine if your target players have fast internet. 
--  -- -- -- -- -- -- -- -- -- -- -- -- -- --	

	damageToSync = {} -- reset table
end
	
addEventHandler("onClientVehicleDamage", root, 
function (attacker, weapon, loss)
	if isElementSyncer(source) and attacker and getElementType(attacker) == "player" and loss > 0 then

		-- register vehicle 
		local vehicleDamageTable = damageToSync[source]
		if not vehicleDamageTable then
			vehicleDamageTable = {}
			damageToSync[source] = vehicleDamageTable
		end
		
		-- register attacker + loss of vehicle
		vehicleDamageTable[attacker] = (vehicleDamageTable[attacker] or 0) + loss
		
		-- start sync delay
		if not syncVehicleDamageTimer then
			syncVehicleDamageTimer = setTimer(syncVehicleDamage, 200, 1)
		end
	end
end)

 

The table structure.


--[[

-- table structure --

local damageToSync = {	
	[vehicle] = {
		[attacker] = loss,
		[attacker] = loss
	}
	[vehicle] = {
		[attacker] = loss,
		[attacker] = loss
	}
}
]]

 

 

Wow, that's awesome. But this will not hurt server when triggering it all the time onClientVehicleDamage? Another question related to it, i will need to get this server-side table when player damage a car (there's a some kind of interface which shows actual armor bar of car), should i make it with triggerClientEvent or there's a better way? About code above, didn't test it yet. 

Link to comment
  • Moderators

 

It will hurt the sender a bit. But only if he or she has terrible internet. And you can always increase the buffer/delay time. (Remember to test the latent version for your target group)

 

 

When you are going to send information back it will also hurt the receiver without doubts. But you can use an even bigger delay for players that are far away. So only the players that are closeby should actually receive data immediately.

On the other hand elementdata could save you some data for closeby players. The usage require less data, but the target players are not control able. So if there are 500 players in your server, then I do not recommended it. You should test both ways.

 

It is a paradox I know...

 

Why not set elementdata clientside? Because players will overwrite the data from each other. It is something the server should manage.

 

Who is your target group by the way?

@majqq

 

Edited by IIYAMA
  • Thanks 1
Link to comment
  • Scripting Moderators
8 hours ago, IIYAMA said:

 

It will hurt the sender a bit. But only if he or she has terrible internet. And you can always increase the buffer/delay time. (Remember to test the latent version for your target group)

 

 

When you are going to send information back it will also hurt the receiver without doubts. But you can use an even bigger delay for players that are far away. So only the players that are closeby should actually receive data immediately.

On the other hand elementdata could save you some data for closeby players. The usage require less data, but the target players are not control able. So if there are 500 players in your server, then I do not recommended it. You should test both ways.

 

It is a paradox I know...

 

Why not set elementdata clientside? Because players will overwrite the data from each other. It is something the server should manage.

 

Who is your target group by the way?

@majqq

 

 

I had already experience with elementData, on 40~ players, let's say was around 15 cars shooting to themselves, and the value of each car armor was done on elementData. There was also one elementData which was responsible for player blood. About my players. I have server in EU, a lot of EU players (they have very small ping 40-60 +/-), and some RU/UA/KZ players (they have ping around 100-120~). I am targeting in making optimisations in everything which changing very frequently (i think it's good to change it from elementData to table), this is one of 3 things, which also change frequently, i just want to see results, which tables can give me. And about this interface, i should send update of this table whenever vehicle got damage?

Edited by majqq
  • Like 1
Link to comment
  • Moderators
38 minutes ago, majqq said:

. And about this interface, i should send update of this table whenever vehicle got damage? 

 

Yes,

 

I can't explain it better than this:

 

Client (see my example)

 

Trigger:

When vehicle damage

 

Condition:

You must be the syncer of the vehicle.

 

Actions:

- Save updates for the table. (Not a new version of the main table)

- Start the buffer timer. 200ms?(if not running already) In case of firedamage or a minigun you will be preventing a trigger event that is send every frame.

 

---------------

 

Trigger:

When the buffer timer is finished.

 

Action:

Send the table updates to the server.

 

_______________

_______________

_______________

 

 

Server

 

Trigger:

When there is an update from the client.

 

Condition:

If a player is closer to the vehicle than 300+ units, do action 1 for him. Else do action 2 for him.

 

Action 1:

Send a (latent) trigger event to the selected person.

 

Action 2:

Save this message in a table. Start a personal buffer timer for him. This table could contain similar types of updates from different vehicles. The data should contain is a reference to the player and to the vehicle. Which you can use to pick the right and latest update for the player.

(Also here start the buffer timer only when it is not running for the selected person)

 

--------------

 

Trigger:

When the personal buffer timer is finished.(action 2)

Action:

Send the table new table to the client.

 

 

Edited by IIYAMA
  • Thanks 1
Link to comment
  • Scripting Moderators
On 13/02/2019 at 17:49, IIYAMA said:

 

Yes,

 

I can't explain it better than this:

 

Client (see my example)

 

Trigger:

When vehicle damage

 

Condition:

You must be the syncer of the vehicle.

 

Actions:

- Save updates for the table. (Not a new version of the main table)

- Start the buffer timer. 200ms?(if not running already) In case of firedamage or a minigun you will be preventing a trigger event that is send every frame.

 

---------------

 

Trigger:

When the buffer timer is finished.

 

Action:

Send the table updates to the server.

 

_______________

_______________

_______________

 

 

Server

 

Trigger:

When there is an update from the client.

 

Condition:

If a player is closer to the vehicle than 300+ units, do action 1 for him. Else do action 2 for him.

 

Action 1:

Send a (latent) trigger event to the selected person.

 

Action 2:

Save this message in a table. Start a personal buffer timer for him. This table could contain similar types of updates from different vehicles. The data should contain is a reference to the player and to the vehicle. Which you can use to pick the right and latest update for the player.

(Also here start the buffer timer only when it is not running for the selected person)

 

--------------

 

Trigger:

When the personal buffer timer is finished.(action 2)

Action:

Send the table new table to the client.

 

 

 

Thanks, but can you help me one more time? I don't want create other topic for it, and question it's related with tables.

How can i send this table from server-side within triggerClientEvent, and then create same, just with other title? Or copy everything what it contains?

table = {
	
	first = {},
	second = {},

}

 

Link to comment
  • Moderators

Clientside

local thisTable = {}


addEvent("update-------")
addEventHandler("update-------", resourceRoot, 
function (index, data) 
	thisTable[index] = data
end, false)

 

Serverside

local thisTable = {}

function updateTable (target, index, data)
	thisTable[index] = data
	triggerLatentClientEvent(target, "update-------", resourceRoot, index, data)
end

updateTable(target, "index", {"data"}) -- all players

updateTable(getElementsByType("player"), "index", {"data"}) -- all players

updateTable(getRandomPlayer(), "index", {"data"}) -- just a single player

updateTable({getRandomPlayer()}, "index", {"data"}) -- just a single player

 

Keep in mind that when testing this code, it is important to mind "when/timing?" + "triggerClientEvent/communication".

As in this example the client hasn't loaded it's scripts yet. Adjust it to your needs.

 

 

@majqq

 

Edited by IIYAMA
  • Thanks 1
Link to comment
  • 3 weeks later...
  • Scripting Moderators
On 15/02/2019 at 12:24, IIYAMA said:

Clientside


local thisTable = {}


addEvent("update-------")
addEventHandler("update-------", resourceRoot, 
function (index, data) 
	thisTable[index] = data
end, false)

 

Serverside


local thisTable = {}

function updateTable (target, index, data)
	thisTable[index] = data
	triggerLatentClientEvent(target, "update-------", resourceRoot, index, data)
end

updateTable(target, "index", {"data"}) -- all players

updateTable(getElementsByType("player"), "index", {"data"}) -- all players

updateTable(getRandomPlayer(), "index", {"data"}) -- just a single player

updateTable({getRandomPlayer()}, "index", {"data"}) -- just a single player

 

Keep in mind that when testing this code, it is important to mind "when/timing?" + "triggerClientEvent/communication".

As in this example the client hasn't loaded it's scripts yet. Adjust it to your needs.

 

 

@majqq

 

 

Hey, @IIYAMA i am glad about to say that your code works perfectly. I did some changes to it - changed source to colshape data, etc., and i encountered a problem on my way to finish this. 

\vehicles.lua:15: attempt to perform arithmetic on local 'damage' (a table value)

This is code, added also colshape data (parent) to identify vehicle later:

triggerLatentServerEvent("sendDataToServer", resourceRoot, parent, damageToSync)

 

So basically it sends a table, not value of damage for certain car, how can i fix it?

This is server-side event which is triggered.

function sendDataToServer(index, damage)
	vehiclesCacheData.armorPoints[index] = vehiclesCacheData.armorPoints[index] - damage -- shows error here
	triggerLatentClientEvent("receiveVehicleData", resourceRoot, index, damage)
end
addEvent("sendDataToServer", true)
addEventHandler("sendDataToServer", resourceRoot, sendDataToServer)

 

Link to comment
  • Moderators
40 minutes ago, majqq said:

 

Hey, @IIYAMA i am glad about to say that your code works perfectly. I did some changes to it - changed source to colshape data, etc., and i encountered a problem on my way to finish this. 


\vehicles.lua:15: attempt to perform arithmetic on local 'damage' (a table value)

This is code, added also colshape data (parent) to identify vehicle later:


triggerLatentServerEvent("sendDataToServer", resourceRoot, parent, damageToSync)

 

So basically it sends a table, not value of damage for certain car, how can i fix it? 

This is server-side event which is triggered.


function sendDataToServer(index, damage)
	vehiclesCacheData.armorPoints[index] = vehiclesCacheData.armorPoints[index] - damage -- shows error here
	triggerLatentClientEvent("receiveVehicleData", resourceRoot, index, damage)
end
addEvent("sendDataToServer", true)
addEventHandler("sendDataToServer", resourceRoot, sendDataToServer)

 

Shouldn't you send the update of the table, instead of the table itself? Hmmm

 

I am currently a bit slow to keep up with your development. Can you take a step back so that I can follow it?

Link to comment
  • Scripting Moderators
1 hour ago, IIYAMA said:

Shouldn't you send the update of the table, instead of the table itself? Hmmm

 

I am currently a bit slow to keep up with your development. Can you take a step back so that I can follow it?

Maybe i didn't understand everything correctly. I made this in some other way.

- Once you create a vehicle, it inserts vehicle in table with data, and send it to players. (vehicle interface) - delay: 60 seconds for player

- When you repair a vehicle, it update data for certain vehicle in table, and send it to players. (vehicle interface)  -  delay: 60 seconds for player

* This is only for the players connected to server. Some players can join later, they would need to have same data as players which have been before latejoiners.

So:

- Once a player login, a triggerLatentClientEvent from server it's sended directly to him, to copy whole data from server-side table, which should be up-to-date all the time, and it replaces (most-likely empty at this moment) client-side table with vehicles data.

About data in tables - i delete cache for certain vehicles from both tables, onVehicleExplode on server-side and onClientElementDestroy (after about 30 seconds) on client-side.

 

And about question. Shouldn't it work? Vehicle got damage > client send triggerLatentServerEvent with damage value > server checks it, updates a server-side table, and send updated data to clients with triggerLatentClientEvent. (Tested it alone, data was correct for every vehicle, after reconnect too.)

 

Edited by majqq
Link to comment
  • Moderators
43 minutes ago, majqq said:

Maybe i didn't understand everything correctly. I made this in some other way.

- Once you create a vehicle, it inserts vehicle in table with data, and send it to players. (vehicle interface) - delay: 60 seconds for player

- When you repair a vehicle, it update data for certain vehicle in table, and send it to players. (vehicle interface)  -  delay: 60 seconds for player

* This is only for the players connected to server. Some players can join later, they would need to have same data as players which have been before latejoiners.

So:

- Once a player login, a triggerLatentClientEvent from server it's sended directly to him, to copy whole data from server-side table, which should be up-to-date all the time, and it replaces (most-likely empty at this moment) client-side table with vehicles data.

About data in tables - i delete cache for certain vehicles from both tables, onVehicleExplode on server-side and onClientElementDestroy (after about 30 seconds) on client-side.

 

And about question. Shouldn't it work? Vehicle got damage > client send triggerLatentServerEvent with damage value > server checks it, updates a server-side table, and send updated data to clients with triggerLatentClientEvent. (Tested it alone, data was correct for every vehicle, after reconnect too.)

 

 

 

Oke, it is growing rapidly I can see.

 

Well then, how to BLOCK incorrect new data before you letting it flows in to your collection of all data:

if damage and type(damage) == "number" then
	local vehicleArmorPoints = vehiclesCacheData.armorPoints[index]
	if vehicleArmorPoints and type(vehicleArmorPoints) == "number" then
		vehiclesCacheData.armorPoints[index] = vehicleArmorPoints - damage
	else
		outputDebugString("`vehicleArmorPoints` should contain a number, but it contains: "  .. inspect(vehicleArmorPoints), 2)
	end
else
	outputDebugString("`damage` should contain a number, but it contains: "  .. inspect(damage), 2)
end

 

If it enters your collection, then you are more or less ** *** ** **** *** ***! because everything that relies on it will break.

Might not be the case in your example, but `better safe than sorry`.

Edited by IIYAMA
  • Thanks 1
Link to comment
  • Scripting Moderators
3 minutes ago, IIYAMA said:

 

 

Oke, it is growing rapidly I can see.

 

Well then, how to BLOCK incorrect new data before you letting it flow in to your collection of all data:


if damage and type(damage) == "number" then
	local vehicleArmorPoints = vehiclesCacheData.armorPoints[index]
	if vehicleArmorPoints and type(vehicleArmorPoints) == "number" then
		vehiclesCacheData.armorPoints[index] = vehicleArmorPoints - damage
	else
		outputDebugString("`vehicleArmorPoints` should contain a number, but it contains: "  .. inspect(vehicleArmorPoints), 2)
	end
else
	outputDebugString("`damage` should contain a number, but it contains: "  .. inspect(damage), 2)
end

 

If it enters your collection, then you are more or less ** *** ** **** *** ***! because everything that relies on it will break.

Might not be the case in your example, but `better safe than sorry`.

 

Nah it's not rapid :D, looks like it but it isn't. I have created basics for this system about 1~ month ago. And hardest (for me) things i am doing now (after a lot of other stuff creating. You helped me a lot of with certain things, big thanks to you :D), at nearly end of this which I am doing. So this way should work, I am right?

Quote

Vehicle got damage > client send triggerLatentServerEvent with damage value > server checks it, updates a server-side table, and send updated data to clients with triggerLatentClientEvent

 

Still i don't know how can i get awaiting damage from this table.

-- table structure --

local damageToSync = {	
	[vehicle] = {
		[attacker] = loss,
		[attacker] = loss
	}
	[vehicle] = {
		[attacker] = loss,
		[attacker] = loss
	}
}
]]

 

  • Like 1
Link to comment
  • Moderators
for vehicle, damageData in pairs(damageToSync) do
	local vehicleDamage = 0
	for attacker, damage in pairs(damageData) do
		vehicleDamage = vehicleDamage + damage
	end
	setElementHealth(vehicle, math.max(getElementHealth(vehicle) - vehicleDamage, 0))
end

You can process it for example like that.

 

You might also need to use isElement in this example, as client data can be out of date.

 

Just so you know: it is not the fastest table structure for reading the data, but it is by far the fastest table structure for writing data. <-- please ignore this bull:~.

Edited by IIYAMA
  • Thanks 1
Link to comment
  • Scripting Moderators
On 08/03/2019 at 20:28, IIYAMA said:

for vehicle, damageData in pairs(damageToSync) do
	local vehicleDamage = 0
	for attacker, damage in pairs(damageData) do
		vehicleDamage = vehicleDamage + damage
	end
	setElementHealth(vehicle, math.max(getElementHealth(vehicle) - vehicleDamage, 0))
end

You can process it for example like that.

 

You might also need to use isElement in this example, as client data can be out of date.

 

Just so you know: it is not the fastest table structure for reading the data, but it is by far the fastest table structure for writing data. <-- please ignore this bull:~.

Okey, looks like i have finished this system for vehicles :D

Thanks for help, i will test it soon with players and i will let you know how it works.

One more question, so i wouldn't need to create another topic for it. What exactly does declaring function as 

local

I know what it does if you declare variable as local, but it's the same for function, like will be faster?

Link to comment
  • Moderators
45 minutes ago, majqq said:

Okey, looks like i have finished this system for vehicles :D

Thanks for help, i will test it soon with players and i will let you know how it works.

One more question, so i wouldn't need to create another topic for it. What exactly does declaring function as 


local

I know what it does if you declare variable as local, but it's the same for function, like will be faster?

 

Function names are 1 = 1 variables. So a local function is nothing more than a function saved in a local variable.

And as you know local variables are faster because they have a limited scope. Instead of searching through all global variables, those variables are more or less being a part of the scope.

 

It is like searching for polar bears on the:

  • A the whole world
  • B the North Pole
  • C graveyard

Where will you find that animal first?

 

 

Different ways of writing them + differences in access:

local function functionName ()
	iprint(functionName) -- "function functionName"
end
iprint(functionName) -- "function functionName"


functionName()

 

local functionName = function ()
	iprint(functionName) -- nil NOOOOOOO!
end
iprint(functionName) -- "function functionName"


functionName()

 

local functionName
function functionName ()
	iprint(functionName) -- "function functionName"
end
iprint(functionName) -- "function functionName"


functionName()

 

  • Like 1
  • Thanks 1
Link to comment
  • Scripting Moderators
7 hours ago, IIYAMA said:

 

Function names are 1 = 1 variables. So a local function is nothing more than a function saved in a local variable.

And as you know local variables are faster because they have a limited scope. Instead of searching through all global variables, those variables are more or less being a part of the scope.

 

It is like searching for polar bears on the:

  • A the whole world
  • B the North Pole
  • C graveyard

Where will you find that animal first?

 

 

Different ways of writing them + differences in access:


local function functionName ()
	iprint(functionName) -- "function functionName"
end
iprint(functionName) -- "function functionName"


functionName()

 


local functionName = function ()
	iprint(functionName) -- nil NOOOOOOO!
end
iprint(functionName) -- "function functionName"


functionName()

 


local functionName
function functionName ()
	iprint(functionName) -- "function functionName"
end
iprint(functionName) -- "function functionName"


functionName()

 

So if i don't need use function(s) globally i can make all of them local, and it will be better a bit?

Link to comment
  • Moderators
1 minute ago, majqq said:

So if i don't need use function(s) globally i can make all of them local, and it will be better a bit?

It will be indeed a bit better.

 

But there are three very important downsides:

  • A limit of the amount of local variables per function.
    Quote

    Limit on number: There is a limit to the number of locals per function (MAXLOCALS, typically 200).

    http://lua-users.org/wiki/LocalsVsGlobals


     
  • 100% locals? It basically means that you can't use multiple files. Which will de-increase your own scripting performance.
     
  • An local variable can only be called below it's declaration.

    So this will not work:
    local function test2 ()
    	test() -- input:2: attempt to call a nil value (global 'test')
    end
    
    local function test ()
      
    end
    
    test2()

    But this will:

    local test2, test
    
    function test2 ()
    	test()
    end
    
    function test ()
      
    end
    
    test2()


     

 

  • Thanks 1
Link to comment
  • 2 weeks later...
  • Scripting Moderators
On 11/03/2019 at 20:45, IIYAMA said:

It will be indeed a bit better.

 

But there are three very important downsides:

  • A limit of the amount of local variables per function.
     
  • 100% locals? It basically means that you can't use multiple files. Which will de-increase your own scripting performance.
     
  • An local variable can only be called below it's declaration.

    So this will not work:
    
    local function test2 ()
    	test() -- input:2: attempt to call a nil value (global 'test')
    end
    
    local function test ()
      
    end
    
    test2()
    

    But this will:

    
    local test2, test
    
    function test2 ()
    	test()
    end
    
    function test ()
      
    end
    
    test2()
    


     

 

 

Hey once again. I want merge some script files, about 16~ lua files. Into 2-4 files (1 shared, others client/server side), to make rework easier. It's just about data system and GUI inventory at all (data for vehicles work well :D). I probably misunderstood this:

A limit of the amount of local variables per function.

It's limit for local variables inside function(s)? Or in whole lua file.

Link to comment
  • Moderators
8 hours ago, majqq said:

 

Hey once again. I want merge some script files, about 16~ lua files. Into 2-4 files (1 shared, others client/server side), to make rework easier. It's just about data system and GUI inventory at all (data for vehicles work well :D). I probably misunderstood this:


A limit of the amount of local variables per function.

It's limit for local variables inside function(s)? Or in whole lua file.

A file counts also as a function.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...