Jump to content

IIYAMA

Moderators
  • Posts

    6,056
  • Joined

  • Last visited

  • Days Won

    208

Posts posted by IIYAMA

  1. 3 hours ago, Tekken said:

    Hi, may I ask why is this a bad implementation ?

     

    I can think of a few, no actual numbers to back this up to be honest.

    • The memory access speed. While _G is also a table, the access method is done with a string instead of an integer.
      • There are a lot of items in the _G table, adding a lot of extra items:
        • Will slow down the loopup with the _G table.
        • And might slowdown the lookup time for globals in general. (no proof/numbers here to be honest)
           
      • And on top of that I am not sure if _G (runtime) lookup speed can actually be optimised by the CPU. It is not a regular table after all.
         
    • Making collision/override possible, which is very easy to do in this case. Creating bugs in your code without knowing it.

     

  2. 1 hour ago, Simon54 said:

    How to actually make this work?

    Normally you use a table.

    But if you aren't able to work with those yet. Here is a very dirty way of doing it:

    for index=1,50 do
    	guiSetVisible ( _G["button_"..index.."_img"], true )
    end

    The _G accesses global variables. (variables without the keyword local in front of them)

    ⚠️ It is not recommended to use this method more than once. It is purely to demonstrate how to do it your way. But not the way Lua intended it to be used ⚠️

     

    For working with tables, please take a look at:

     

    • Like 1
    • Thanks 1
  3. On 18/07/2024 at 23:08, Korea said:

    There is a way to 'bypass' it.

    I am aware of how that function works.

     

    But how does this related to your previous code?

    Also example code often require some more instructions/information.

     

    The thing is, I am not sure where to put your content in this case (after your second reply).

    • If you want to publish a resource, sure this is the right location. But just example code is not a resource.
    • Is it a tutorial? It is misses a lot of information/instructions, but close enough.

    What do you want this topic to be?

    You can also create wiki pages for example code.

  4. 1 hour ago, Korea said:
        screen = dxCreateScreenSource(sx, sy) -- your choice

    The dxCreateScreenSource function creates the screenSource element. (it can fail if there is not enough video memory, which results in returning the value false instead)

    Important:
    Elements can't be directly saved inside variable, a variable can only point to an element (see userdata). Thus overriding the value of variable screen, does not delete the previous element. Which leads to a memory leak.

    Recommendation:
    The screenSource texture element should only be created ones at the top of your resource.

    Or you can do something like this:

    if not screen then screen = dxCreateScreenSource(sx, sy) end -- of not exist, attempt to create the screenSource texture
    if screen then dxUpdateScreenSource(screen, true) end -- if exist, update the screenSource

     

    @Korea

    (If you want to me to update your current example, feel free to ask below. Also this topic might be better of at scripting > tutorials, but it is your choice. )

    • Like 1
  5.  

    12 hours ago, DarkStalker30 said:

    1. Can I'll write to your's PM for some questions in future? Looks like you are advanced user and can help with many problems 😅

    You can, but it is sometimes better to ask your main questions here. And if nobody knows the answer, you can always send me a message to a specific topic. There are more people out there that could have provided this answer.

     

    12 hours ago, DarkStalker30 said:

    2. Nothing go bad if I use "root" in client events? Because on wiki was written that root should not use, only in specific moments.

    The variable root is predefined variable, containing the root element pointer.

    https://wiki.multitheftauto.com/wiki/Element_tree

    Which is the great parent of parents ^^. Take a look at the schematic (on the wiki).

    Tre.png

     

    Events work with a kind parent to child relation. Triggering an event on an element with a lot of children can increase CPU usage significant (execution time more or less 0.5% for each child extra, based on a sample created on my specific system).

    • So it is to reduce the CPU usage.
    • But also making sure you do not clash with other resources. Because an event is a global interaction, a resource can trigger an eventHandler for another resource.

    It is recommended to trigger an event with the resourceRoot, a specific element of that resource or a player.

     

    The resourceRoot is a predefined variable that is the root element for a specific resource (See purple nodes in the schematic). 

    • There is a resourceRoot for every resource and each of them is unique.
    • [For each resource]: The resourceRoot of clientside is linked to the resourceRoot of serverside. They are considered more or less the same (In technical terms that is not the case, but you will not notice it).

    The benefit of using resourceRoot is that the eventHandlers that listen to resourceRoot, will only trigger for the same resourceRoot or (by default) their children.

     

    The following example shows how a resource communicates from serverside to clientside. And the communication is scoped with the resource itself.

    • This does not mean that other resources can't listen to the "onGreeting" event, but the eventHandler will not trigger for other resources that run the exact same code.
    -- Server
    
    -- (playerSource is not yet defined)
    triggerClientEvent ( playerSource, "onGreeting", resourceRoot )

     

    -- Client
    addEvent( "onGreeting", true )
    addEventHandler( "onGreeting", resourceRoot, function () end ) -- Default: resourceRoot + children
    
    addEvent( "onGreeting", true )
    addEventHandler( "onGreeting", resourceRoot, function () end, true ) -- resourceRoot + children
    
    addEvent( "onGreeting", true )
    addEventHandler( "onGreeting", resourceRoot, function () end, false ) -- only resourceRoot

     

    See also:

    local thisElement = resourceRoot 
    
    addEvent( "onGreeting", true )
    addEventHandler( "onGreeting", thisElement, function () end ) -- thisElement should have the same value >
    
    -- Triggering an event on the same side(server or client)
    triggerEvent("onGreeting", thisElement) -- > as thisElement or a child of it.

     

    If using root on an eventHandler, it will trigger for all elements, since this is the great parent of parents... All resources will be able to trigger this event, no matter which element they use.

    addEvent( "onGreeting", true )
    addEventHandler( "onGreeting", root, function () end )

     

    Is it possible to trigger the following eventHandler from another resource?

    addEvent( "onGreeting", true )
    addEventHandler( "onGreeting", resourceRoot, function () end )

    Technically yes, elements from another resource are all part of the element tree. So as long as you use the right element, it is possible.

     

     

    (normally I do not explain this much)

     

    • Like 1
  6. 25 minutes ago, [FOTL]Aphex said:

    Any ideas what I'm doing wrong?

     

    Not exactly haha, but I can give you some (bad) advice. How about using some brute force for a starter? (First make it, then optimise it)

    function adjustVehicle()
    	local veh = getPedOccupiedVehicle(localPlayer)
    	if not veh then return end
    	local rx, ry = getElementRotation(veh)
    	if getKeyState("d") then
    		setControlState(localPlayer, "accelerate", true)
    		setElementRotation(veh, rx, ry, 90)
    	elseif getKeyState("a") then
    		setControlState(localPlayer, "accelerate", true)
    		setElementRotation(veh, rx, ry, -90)
    	else
    		setControlState(localPlayer, "accelerate", false)
    	end
    end
    
    addEventHandler("onClientPreRender", root, adjustVehicle)

     

     

     

  7. 21 hours ago, CastiaL said:

    how can I prevent this?

     

    I quickly looked at the code and there seems to be a vulnerability here:

    fr_server.lua

    addEvent('onServerCall', true)
    addEventHandler('onServerCall', resourceRoot,
    	function(fnName, ...)
    		source = client		-- Some called functions require 'source' to be set to the triggering client
    		local fnInfo = g_RPCFunctions[fnName]
    
    		-- Custom check made to intercept the jetpack on custom gravity
    		if fnInfo and type(fnInfo) ~= "boolean" and tostring(fnInfo.option) == "jetpack" then
    			if tonumber(("%.3f"):format(getPedGravity(source))) ~= 0.008 then
    				errMsg("* You may use jetpack only if the gravity is set to 0.008", source)
    				return
    			end
    		end
    
    		if fnInfo and ((type(fnInfo) == 'boolean' and fnInfo) or (type(fnInfo) == 'table' and getOption(fnInfo.option))) then
    			local fn = _G
    			for i,pathpart in ipairs(fnName:split('.')) do
    				fn = fn[pathpart]
    			end
    			----------------------------
    			fn(...) -- LOCATED HERE
    			----------------------------
    		elseif type(fnInfo) == 'table' then
    			errMsg(fnInfo.descr .. ' is not allowed', source)
    		end
    	end
    )

    The given arguments for any of the functions below are not validated.

    Spoiler
    g_RPCFunctions = {
    	addPedClothes = { option = 'clothes', descr = 'Modifying clothes' },
    	addVehicleUpgrade = { option = 'upgrades', descr = 'Adding/removing upgrades' },
    	fadeVehiclePassengersCamera = true,
    	fixVehicle = { option = 'repair', descr = 'Repairing vehicles' },
    	giveMeVehicles = { option = 'createvehicle', descr = 'Creating vehicles' },
    	giveMeWeapon = { option = 'weapons.enabled', descr = 'Getting weapons' },
    	removePedClothes = { option = 'clothes', descr = 'Modifying clothes' },
    	removePedFromVehicle = true,
    	removeVehicleUpgrade = { option = 'upgrades', descr = 'Adding/removing upgrades' },
    	setElementAlpha = { option = 'alpha', descr = 'Changing your alpha' },
    	setElementInterior = true,
    	setMySkin = { option = 'setskin', descr = 'Setting skin' },
    	setPedAnimation = { option = 'anim', descr = 'Setting an animation' },
    	setPedFightingStyle = { option = 'setstyle', descr = 'Setting fighting style' },
    	setPedGravity = { option = 'gravity.enabled', descr = 'Setting gravity' },
    	setPedStat = { option = 'stats', descr = 'Changing stats' },
    	setPedWearingJetpack = { option = 'jetpack', descr = 'Adding/removing a jetpack' },
    	setVehicleColor = true,
    	setVehicleHeadLightColor = true,
    	setVehicleOverrideLights = { option = 'lights', descr = 'Forcing lights' },
    	setVehiclePaintjob = { option = 'paintjob', descr = 'Applying paintjobs' },
    	warpMeIntoVehicle = true,
    }

     

     

  8. You could use for the markers:

    local markers = {
    	{	-- marker data
    		otherProp = '????',
    		element = '<marker element>'
    	},
    	{	-- marker data
    		otherProp = '????',
    		element = '<marker element>'
    	},
    }

     

    20 hours ago, [FOTL]Aphex said:

    With a `for` loop checking/dictating which markers are visible to which players?

    Loops are not needed if you use the `player` as key.

     

    And as for the players and their data:

    ---@type {[userdata]: {[string]: any}}
    local playerData = {}
    
    --- Give a player their own table/data
    ---@param player userdata
    function initPlayerData(player)
    	if playerData[player] then return end
    	playerData[player] = {} -- < sub table
    end
    
    ---@param player userdata
    ---@param key string
    ---@param data any
    function setPlayerData(player, key, data)
    	if not playerData[player] then return end
    	playerData[player][key] = data
    end
    
    ---@param player userdata
    ---@param key string
    ---@return unknown|nil
    function getPlayerData(player, key)
    	if not playerData[player] then return end
    	return playerData[player][key]
    end

    Usage example:

    --- SET
    setPlayerData(player, "nextMarker", marker)
    
    --- GET
    local marker = getPlayerData(player, "nextMarker")

     

     

     

    • Like 1
  9. 1 hour ago, [FOTL]Aphex said:

    So is there any way to only see and affect the markers created on your own client?

    Clientside is basically that.

    Every client=player runs a copy of the same code on their own pc and the (variable) data is not shared.

     

    Going for clientside?

    As long as you do not mind the following, go for it!

    • Cheater can take advantage of this. (for example being able to win in an instance)
    • It is harder to maintain round management/win/lose etc.

    Note: Remote players(other players than yourself) can also trigger some events in your copy of the code. So adding checks like this are important:

    if(hitElement == localPlayer) then

     

    Going for serverside?

    • Using tables is an essential for the serverside version of your current code. ⚠️ If you want to create bug free code on serverside, it is one of the things you have to master first. Tables are used to give every player their own piece of data, for example to keep track of the race/checkpoint progress for every player separately.

     

    1 hour ago, [FOTL]Aphex said:

    but it fried my brain so I figured clientside would be simple

    Simple does not always equal better unfortunately. Give serverside a try if you are ready for it, but shouldn't be ignored completely. You are playing a multiplayer game after all.

  10. 2 hours ago, #nofear said:

    Please evaluate the original version of the Server.lua section of the Login Panel.

     

    Here is a fix for a vulnerability for cheaters to abuse (else cheaters can create accounts for other players):

    addEvent("onAccountManage", true)
    addEventHandler("onAccountManage", root, function(typ, username, password, save_log)
    	if source ~= client then return end -- Fix vulnerability

     

    The addAccount function returns the new created account, but can fail. Not the end of the world.

    addAccount(username, password)

     

    Are there any errors in this code?

    I can't find the variable declaration of idTablo, is this one located in another file?

     

     

  11. 5 minutes ago, szampan said:

    The event could be faked by the client, but im just using a variable rn instead

    Yea true, but everything can be faked, even files.

    But that does not mean that you can't personalize data based on user specifications mixed with salt/private key.

     

    6 minutes ago, szampan said:

    can close

    actually in my scenario i would always know if the client faked it but either way i have found a new solution

    I will lock/close your topic, good luck with your new solution!

    • Like 1
  12. On 04/07/2024 at 17:44, #nofear said:

    However, I'm unable to resolve the error in this login panel.

    There are a lot of things wrong with this code. I also noticed that the code contains both tabs and spaces, which mean two different users have been messing with this code (80% sure). And on top of that 50% of the code is broken... 🤦‍♂️

    I have fixed the spaces/tabs for you, and showed you where mistakes are located. But the rest is up to you, especially since I have not clue how this is suppose to be working.

     

    function getIDFromPlayer(id)
    	if id then
    		local theid                 -- Issue: not defined
    		idTablo = getElementsByType("id") -- Issue: Returns a table of elements, the order can vary and the index does not necessary means it's the correct it.
    		for id, p in pairs(idTablo) do
    			if id == p then         -- Issue: Comparing integer with an element
    				theid = i           -- Issue: `i` not defined
    				-- Issue: loop should have been broken with `break`
    			end
    		end
    		return theid
    	else
    		return false
    	end
    end
    
    function getPlayerFromID(id)
    	if id then
    		id = tonumber(id)             -- Issue: tonumber should be before the `if id then`
    		local theplayer               -- Issue: Value is nil
    		idTablo = getElementsByType("id") -- Issue: Returns a table of elements, the order can vary and the index does not necessary means it's the correct it.
    		for id, p in pairs(idTablo) do
    			if theID == id then       -- Issue: theID is not defined, comparing nil with integer
    				theplayer = p
    				-- Issue: loop should have been broken with `break`
    			end
    		end
    		return theplayer
    	else
    		return false
    	end
    end
    
    addEventHandler("onPlayerLogin", root, function(_, hesap)
    	setElementData(source, "loggedin", true)
    	setElementData(source, "TuningMenuTrue", false)
    	local hesapID = getAccountID(hesap)
    	if idTablo[hesapID] then  -- Issue: idTablo might not be defined
    		ozelID = idTablo[hesapID]
    		setElementID(source, ozelID) -- ozelID if from getElementsByType is an element, not an integer/string
    	else
    		setElementID(source, hesapID)
    	end
    	local oyuncu = (string.gsub(getPlayerName(source), "#%x%x%x%x%x%x", ""))
    	local id = getElementID(source) or "-1"
    	-- Variable `oyuncu` and `id` not being used
    end)
    
    addEventHandler("onResourceStart", resourceRoot, function()
    	-- Issue: `id` is not defined
    	if id then
    		id = tonumber(id) -- Issue: tonumber should be before the `if id then`
    		local theplayer -- Issue: Value is nil
    		idTablo = getElementsByType("id")
    		for id, p in ipairs(getElementsByType("player")) do
    			-- Issue: neither variable `id` nor `p` are being used
    			-- Issue: player is not defined. (shouldn't have been variable `p`?)
    			setElementData(player, "loggedin", not isGuestAccount(getPlayerAccount(player)))
    			setElementData(player, "TuningMenuTrue", isGuestAccount(getPlayerAccount(player)))
    			if getPlayerAccount(player) then
    				local hesapID = getAccountID(getPlayerAccount(player))
    				if idTablo[hesapID] then
    					ozelID = idTablo[hesapID] -- Issue: Should be a local, ozelID is an element, not an id
    					setElementID(player, ozelID) -- ozelID if from getElementsByType is an element, not an integer/string
    				end
    			end
    		end
    	end
    end)

     

  13. 12 hours ago, tzn said:

    Hello, why is the message sent by the player not canceled?

    Most likely because of another resource.

     

    Use the AddDebugHook function on outputChatBox, to figure out which one. (this function shows you where a MTA function is called or event is triggered)

  14. 6 hours ago, #nofear said:

     The player dies but does not appear to have left the area.

    If these are the only lines of code that trigger 'destroyTimers'/'destroyTrepassor', then I don't think you have to check element data on clientside.

     

    But if they are not, you could use triggerClientEvent arguments instead. But keep in mind that the clientside handler functions also has to do other things, else it doesn't make sense to have the condition isInResArea in the first place.

     

    Server

    triggerClientEvent ( 
    	pla, -- receiver (player)
    	"destroyTrepassor", 
    	g_root, -- source
    	true -- < isInResArea 
    )

     

    Clientside

    addEvent ( "destroyTrepassor", true )
    addEventHandler ( "destroyTrepassor", g_loc_root,
    	function (isInResArea)
    		-- ...
    		if isInResArea == true then
          
    		-- ...

     

×
×
  • Create New...