-
Posts
6,058 -
Joined
-
Last visited
-
Days Won
208
Everything posted by IIYAMA
-
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()
-
It will fill up the client message buffer. Just read my crap or just do it and find out. Note: for trigger[client/server]Events TCP messages are used and not UDP messages. Just a quick summary of those two communication protocols and why I do not recommend you doing that. (to save you some time) TCP = 100% success rate if the client remains connected and able to receive messages. In case of failure the message will be automatic resend. In case of success a message will be send back to inform the sender that the message has been delivered. Messages will be send in order, one at the time. The rest have to wait in queue. ? Available for scripting UDP = success rate is not measure able, because there is no validation if a message has been received or not. Method often used for streaming or for sending large files in pieces. NOT AVAILABLE for scripting In case of streaming (every frame) with TCP = trigger[client/server]Events + message 1 (frame 1) Sending message 1. + message 2 (frame 2) + message 3 (frame 3) + message 4 (frame 4) + message 5 (frame 5) + message ... + message 30 (frame 30) Receive response from message 1. Messages in queue: 29! Sending message 2. + message 31 (frame 31) + message 32 (frame 32) + message ... + message 60 (frame 60) Receive response from message 2. Messages in queue: 58! + message 61 (frame 61) + message 62 (frame 62) + message ... + message 90 (frame 90) Receive response from message 3. Messages in queue: 87! CONNECTION TROUBLE ;@ CONNECTION TROUBLE CONNECTION TROUBLE CONNECTION TROUBLE CONNECTION TROUBLE CONNECTION TROUBLE CONNECTION TROUBLE CONNECTION TROUBLE CONNECTION TROUBLE ... CONNECTION LOST You do not have to do this every frame. The events are already there for you. And this will not be any different from how it currently works.
-
It is not possible when doing it based on two sides, unless the system time is set at the exact same time, while both systems are standing next to each other. There is only one way to reduce the connection delay + serverside and that is to buy multiple servers in other countries which will give the start signal and receive the end signal. But which person is willing to go that far? There is one real realistic thing you can do. Which is prioritise the connection. Use triggerClientEvent to start the race. And use triggerServerEvent to end the race. So instead of onColShapeHit use onClientColShapeHit + triggerServerEvent. This should be faster, but make sure to validate that so that you know for sure, that I am not talking crap. (I am not a MTA developer after all)
-
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()
-
You might also be able to use CEF to create button textures. (Haven't done it before, but it looks to me that it is very well possible)
-
@Zcraks Don't use the two codes in each other... ! The variable windContainer doesn't have to leave it's environment. It will only be used where it is needed! if wind and isElement(windContainer) () then The existence of wind has nothing to do with the existence of windContainer. This parent/container exists always. BUT the existence of wind is related to the children count of the windContainer. So if there are no children, then there is no wind to destroy. Just read the function names, those explain a lot. createWind = Creating a wind element. destroyWind = Destroying all wind elements. (by destroying it's parent) doesWindExist = Check if there are any wind elements. (based on children count of the parent) do local windContainer = createElement("windContainer") -- parent function createWind (...) local wind = createObject(...) if wind then setElementParent(wind, windContainer) -- make wind a child of windContainer return wind end return false end function destroyWind () if doesWindExist () then destroyElement(windContainer) windContainer = createElement("windContainer") return true end return false end function doesWindExist () return getElementChildrenCount ( windContainer ) > 0 end end function checkTime () local timehour, timeminute = getTime() if timehour <= 19 and timehour >= 6 then destroyWind() elseif not doesWindExist () then createWind(3892,-2072.5,285.5,34.3, 0,0,0) createWind(3895,-2035.6,263.39999,34.3, 0,0,0) createWind(3896,-2096.5,146.5,34.3, 0,0,0) createWind(3897,-2056.1001,214.8,34.3, 0,0,0) outputChatBox ("Object created") end end addEventHandler( "onClientRender", getRootElement( ),chekTime)
-
Keep both codes separated like I did. 0. Restore the code before you applied the changes from my code. 1. Copy the first code 100% in yours. (On top of your script file?) 2. The second code is an edited version of your code. Check which changes I made in compare to yours. For example: createObject is now replaced with createWind. Which also creates an object and rerurns it. Not that you have to use the returned value in anyway. I have more or less already done 90% for you... so no stress, just observe and apply.
-
do local windContainer = createElement("windContainer") -- parent function createWind (...) local wind = createObject(...) if wind then setElementParent(wind, windContainer) -- make wind a child of windContainer return wind end return false end function destroyWind () if doesWindExist () then destroyElement(windContainer) windContainer = createElement("windContainer") return true end return false end function doesWindExist () return getElementChildrenCount ( windContainer ) > 0 end end This can be done by using propagation on the element tree. This means that if you use an element based function(Example: destroyElement) on a specific PARENT(Example: windContainer) element, it's CHILDREN(Example: wind, wind, wind) elements will also apply this function. Might be hard to understand, but it is easier than doing it with tables. if timehour <= 19 and timehour >= 6 then destroyWind() elseif not doesWindExist () then wind = createWind(3892,-2072.5,285.5,34.3, 0,0,0) wind = createWind(3895,-2035.6,263.39999,34.3, 0,0,0) wind = createWind(3896,-2096.5,146.5,34.3, 0,0,0) wind = createWind(3897,-2056.1001,214.8,34.3, 0,0,0) outputChatBox ("Object created") The element tree of MTA looks a bit like HTML if you have ever worked with that. https://wiki.multitheftauto.com/wiki/Element_tree
-
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:~.
-
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`.
-
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?
-
Is the gate used in an interior? If yes, then you also have to change that: https://wiki.multitheftauto.com/wiki/SetElementInterior
-
Nice work! I updated the code in the tutorial.
- 21 replies
-
- onclienthudrender
- onclientprerender
-
(and 1 more)
Tagged with:
-
That you do not have a super computer that can read > convert > play(at location) a sound within 1ms. Can't you do it in an x amount of time in the future? Atleast convert it to a wav format, else it has to re-uncompress the file.
-
@xuaNN The bar element: local bar = DGS:dgsCreateImage(0.7 * fScreenX, 0 * fScreenY, 0.24 * fScreenX, 1 * fScreenY,_,false,_,tocolor(0,0,0,225)) Is not available here: addEventHandler("onDgsMouseClick",bar,buttonClick) Either: - The addEventHandler is placed higher in the code, than where the bar is created. - The addEventHandler is placed in another file, than where the bar is created. - Or the bar has not been created at all.
-
@xuaNN Where did you define the `bar` variable? (created the button)
-
Obvious, at the place where you want to use a timer. It is your code, you know that best.
-
@Quenix There is no timer function in this code... In case you use a timer function and you want to pass arguments: function remindMe (arg1, arg2) iprint(arg1, arg2) end ------------------- local arg1 = "argument1" local arg2 = "argument2" setTimer(remindMe, 1000, 1, arg1, arg2)
-
then you should start with an array structured table and create and object structured table afterwards. Start with an array structured table. local tableTestArray = { {key = "Room1"}, {key = "Room2"}, {key = "Room3"}, {key = "Room4"} } local tableTestObject = {} for i=1, #tableTestArray do tableTestObject[tableTestArray[i].key] = tableTestArray[i] end This allows you to access the data with multiple ways. access to ipairs (loop in order) --> tableTestArray access to # (item count) --> tableTestArray access with "Room1" --> tableTestObject NOTE: the sub tables are LINKED between: tableTestArray <> tableTestObject They are the same.
-
ipairs loop only works an array structure tables. indexes: 1,2,3,4 The # only works for array structured tables. But yours is an object/custom structured table. indexes: 'Room1', 'Room2', 'Room3', 'Room4' And for that you need the pairs loop function getTableCount(thisTable) local count = 0 for k, v in pairs(thisTable) do count = count + 1 end return count end local count = getTableCount(tableTest) @Overkillz
-
then it is: if timehour == 6 then or not executed at all.
-
if timehour == 6 then if wind and isElement(wind) then destroyElement(wind) wind = nil outputChatBox ("Object destroyed") end elseif not wind or not isElement(wind) then wind = createObject(1337,2321.5, -1659.5,13.5) outputChatBox ("Object created") end @Zcraks
-
If you use Globals, you will be overwriting the variables. for i = 1, 40 do local Gate3 = createObject ( 5020, -2660.8000488281, 1424.8000488281, 921.20001220703, 0, 0, 270 ) setElementDimension( Gate3, i ) local x,y,z = getElementPosition (Gate3) local Zona = createColCircle ( x,y, 3, 3 ) local function Portao7(thePlayer) for _, group in ipairs ({"Console"}) do if isObjectInACLGroup ( "user." .. getAccountName(getPlayerAccount(thePlayer)), aclGetGroup( group )) then moveObject (Gate3, 3000, -2660.8000488281, 1424.8000488281, 923 ) end end end addEventHandler ( "onColShapeHit", Zona, Portao7 ) -- not> Portao5 local function Portao8(thePlayer) for _, group in ipairs ({"Console"}) do if isObjectInACLGroup ( "user." .. getAccountName(getPlayerAccount(thePlayer)), aclGetGroup( group )) then moveObject (Gate3, 3000, -2660.8000488281, 1424.8000488281, 921.20001220703 ) end end end addEventHandler ( "onColShapeLeave", Zona, Portao8 ) -- not> Portao6 end
-
As far as I know these settings are only used for sync element orientations. p.s you might also reduce data like this: function onClientPlayerDamage(attacker, weapon, bodypart, loss) local newHealth = getElementHealth(localPlayer) if newHealth > 0 then -- is not dead local oldHealth = newHealth + loss setElementHealth(localPlayer, oldHealth) -- reset else -- is dead cancelEvent() triggerLatentServerEvent("onPlayerDamage_", localPlayer, attacker, weapon, bodypart, loss) end end addEventHandler("onClientPlayerDamage", localPlayer, onClientPlayerDamage) p.s this might also be needed serverside. addEvent("onPlayerDamage", false) --remote disabled