John Smith Posted July 17, 2015 Share Posted July 17, 2015 is it possible in some way to unload a code which was injected with loadstring? as far as i see, only solution to this would be restarting the resource which has loadstring in it's code any other (perhaps better) solutions? Link to comment
GTX Posted July 17, 2015 Share Posted July 17, 2015 Yes, do wrappers, override functions, store them into table and then destroy them if they're elements or set them to their default state or whatever. EDIT: An example would be: -- Override the function. _playSound = playSound sounds = {} res = "" function playSound(filepath, looped) local music = _playSound("cache/"..res.."/"..filepath, looped) -- Filepath is song (music.mp3) if music then table.insert(sounds, music) -- You can unload it later. Just loop through this table and use stopSound. end end function loadScript(content, resourceName) res = resourceName -- Your map name. local loadit = loadstring(content) local loaded = pcall(loadit) if loaded then -- ? end end Link to comment
John Smith Posted July 17, 2015 Author Share Posted July 17, 2015 So simply overriding default functions in main script file to my needs will send the overriden functions via loadstring(e.g playSound) instead of default functions? Link to comment
John Smith Posted July 18, 2015 Author Share Posted July 18, 2015 I dont know if you understood my previous post, but wrapper thing seems to work! Thank you this is what i used local files = { "server.lua" }; _outputChatBox = outputChatBox; outputChatBox = function() end; function loadScripts() for _,v in pairs(files) do local file = fileOpen(v); local content = fileRead(file,fileGetSize(file)); loadstring(content)(); fileClose(file); end; end; setTimer(loadScripts,50,1); Link to comment
GTX Posted July 18, 2015 Share Posted July 18, 2015 Glad it helped! If you want to reuse function, use _outputChatBox as in your example. Link to comment
John Smith Posted July 23, 2015 Author Share Posted July 23, 2015 hello, i have tried making wrapper(i prefer calling it overrider) but it doesnt work properly for some reason this is example of one function which doesnt work properly in overrider _playSound = playSound; function playSound(path,looped) _outputChatBox("custom playSound path "..path,255,0,0) -- this playSound function doesn't even get executed sound = _playSound(path,looped); if sound then table.insert(arena.sounds,sound); end; end; function loadScript(res,script) currentResource = getResourceFromName(res); local path = ":"..getResourceName(currentResource).."/"..script; local file = fileOpen(path); local content = fileRead(file,fileGetSize(file)); local f = loadstring(content) pcall(f); fileClose(file); end; addEvent("onScriptLoadRequest",true); addEventHandler("onScriptLoadRequest",root,loadScript); this script above for example loads this map script: function startMusic() setRadioChannel(0) song = playSound("music2.mp3",true) outputChatBox("#ffffff* #C0FF3ETurn on/off Music Using #FFFFFF\"M\"",255,255,255,true) end function makeRadioStayOff() setRadioChannel(0) cancelEvent() end function toggleSong() if not songOff then setSoundVolume(song,0) songOff = true removeEventHandler("onClientPlayerRadioSwitch",getRootElement(),makeRadioStayOff) else setSoundVolume(song,1) songOff = false setRadioChannel(0) addEventHandler("onClientPlayerRadioSwitch",getRootElement(),makeRadioStayOff) end end addEventHandler("onClientResourceStart",getResourceRootElement(getThisResource()),startMusic) addEventHandler("onClientPlayerRadioSwitch",getRootElement(),makeRadioStayOff) addEventHandler("onClientPlayerVehicleEnter",getRootElement(),makeRadioStayOff) addCommandHandler("musicmusic",toggleSong) bindKey("m","down","musicmusic") addEventHandler("onClientResourceStop",getResourceRootElement(getThisResource()),startMusic) and it loads the code provided but for example it doesn't play music and when i press key M it says WARNING: Bad 'sound/player' pointer @ 'setSoundVolume'(1) [string "function startMusic()..."] i would appreciate if you could help me solve this issue Link to comment
novo Posted July 23, 2015 Share Posted July 23, 2015 Though there are many security-issues related to loading code that way, the one-issue you're going through on your last post is you are not triggering onClientResourceStart, event responsible of executing startMusic function (as, this way, you are not running a resource on its own and thus such event is not being run). Link to comment
GTX Posted July 23, 2015 Share Posted July 23, 2015 Like novo said, you must override addEventHandler. local events = {} _addEventHandler = addEventHandler function addEventHandler(event, element, func) if func then if event == "onClientResourceStart" then func() else if _addEventHandler(event, element, func) then events[#events+1] = {event, element, func} end end end end And then also unload it with removeEventHandler. I suggest also to store all functions and variables into own environment using setfenv. Link to comment
novo Posted July 23, 2015 Share Posted July 23, 2015 I suggest also to store all functions and variables into own environment using setfenv. That basically is what you should do in order to avoid most security issues and in case you want to run all the functions attached to onClientResourceStart, simply set another event name for the handler that you can afterwards manually-trigger in order to execute all those functions simultaneously (without actually triggering onClientResourceStart). Link to comment
John Smith Posted July 23, 2015 Author Share Posted July 23, 2015 thanks, i've already overriden addEventHandler but didn't add that onClientResourceStart part.. about function enviorment: i've never rly worked with it, i tried it in my code but it messed everything up so for now i'd just like to stick to not secure way until this starts working however i am having issues with this overrider here are some parts of code that could be causing unwanted things: function unloadScripts() environment = nil; -- currently not being even used currentResource = nil; dimension = nil; for _,v in pairs(arena.sounds) do stopSound(v); destroyElement(v); --returns warning, probably impossible thing to do anyway? end; for _,v in pairs(arena.txds) do destroyElement(v); end; for _,v in pairs(arena.dffs) do engineRestoreModel(v); end; for _,v in pairs(arena.cols) do engineRestoreCOL(v); end; for _,v in pairs(arena.markers) do destroyElement(v) end; for _,v in pairs(arena.objects) do destroyElement(v); end; for _,v in pairs(arena.vehicles) do destroyElement(v); end; for _,v in pairs(arena.peds) do destroyElement(v); end; for _,v in pairs(arena.handlers) do removeEventHandler(v[1],v[2],v[3]); end; for _,v in pairs(arena.binds) do unbindKey(v[1],v[2],v[3]); end; for _,v in pairs(arena.commands) do removeCommandHandler(v[1],v[2]); end; setWaterLevel(0) resetSkyGradient() resetWaterColor() resetWaterLevel() setWaveHeight(0) resetHeatHaze() resetWindVelocity() resetAmbientSounds() resetWorldSounds() resetRainLevel() resetSunSize() resetSunColor() resetFogDistance() resetFarClipDistance() setGravity(0.008) setGameSpeed(1) setCloudsEnabled(false) arena = { sounds = {}; -- done dffs = {}; -- done txds = {}; -- done cols = {}; -- done objects = {}; -- done markers = {}; -- done vehicles = {}; -- done peds = {}; -- done handlers = {}; -- done binds = {}; -- done commands = {}; -- done }; _outputChatBox("onScriptUnloadRequest") end; addEvent("onScriptUnloadRequest",true); addEventHandler("onScriptUnloadRequest",root,unloadScripts); addEventHandler("onClientResourceStop",resourceRoot,unloadScripts); thing seem to work fine when map first time initializes, but after unloadScripts() it doesn't work anymore. simply the scripts dont get loaded should i give more info or something? i dont have any specific errors considering this Link to comment
novo Posted July 23, 2015 Share Posted July 23, 2015 destroyElement is not working there cause when stopSound is executed, (...) the sound element is also destroyed. Also, may you provide us the full code you're running? I do not see any mistake over here. Link to comment
John Smith Posted July 23, 2015 Author Share Posted July 23, 2015 _playSound = playSound; _engineLoadTXD = engineLoadTXD; _engineReplaceModel = engineReplaceModel; _engineReplaceCOL = engineReplaceCOL; _createMarker = createMarker; _createObject = createObject; _createVehicle = createVehicle; _createPed = createPed; _addEventHandler = addEventHandler; _outputChatBox = outputChatBox; _getThisResource = getThisResource; _bindKey = bindKey; _addCommandHandler = addCommandHandler; --todo engineLoadDFF --todo dxCreateShader local environment = {}; local currentResource; local arena = { sounds = {}; -- done dffs = {}; -- done txds = {}; -- done cols = {}; -- done objects = {}; -- done markers = {}; -- done vehicles = {}; -- done peds = {}; -- done handlers = {}; -- done binds = {}; -- done commands = {}; -- done }; local dimension = 0; --outputChatBox = function() end; function playSound(path,looped) _outputChatBox("custom playSound path "..path,255,0,0) sound = _playSound(":"..getResourceName(currentResource).."/"..path,looped); if sound then table.insert(arena.sounds,sound); end; return sound end; function engineLoadTXD(path) local txd = _engineLoadTXD(":"..getResourceName(currentResource).."/"..path); table.insert(arena.txds,txd) return txd; end; function engineReplaceModel(dff,model) table.insert(arena.dffs,model); return _engineReplaceModel(dff,model); end; function engineReplaceCOL(col,model) table.insert(arena.cols,model); return _engineReplaceCOL(col,model); end; function createMarker(...) local marker = _createMarker(...); setElementDimension(marker,dimension) table.insert(arena.markers,marker); return marker; end; function createObject(...) local object = _createObject(...); setElementDimension(object,dimension) table.insert(arena.objects,object); return object; end; function createVehicle(...) local veh = _createVehicle(...); setElementDimension(veh,dimension) table.insert(arena.vehicles,veh); return veh; end; function createPed(...) local ped = _createPed(...); setElementDimension(ped,dimension); table.insert(arena.peds,ped); return ped; end; function addEventHandler(eventName,attachedTo,handlerFunction,getPropagated,priority) if eventName == "onClientResourceStart" then setTimer(handlerFunction,1000,1) end; table.insert(arena.handlers,{eventName,attachedTo,handlerFunction}); return _addEventHandler(eventName,attachedTo,handlerFunction,getPropagated,priority); end; function getThisResource() return currentResource; end; function bindKey(key,keystate,...) table.insert(arena.binds,{key,keystate,...}); return _bindKey(key,keystate,...); end; function addCommandHandler(name,func,caseSensitive) table.insert(arena.commands,{name,func,caseSensitive}); return _addCommandHandler(name,func,caseSensitive); end; function loadScript(res,script) dimension = getElementDimension(source); currentResource = getResourceFromName(res); local path = ":"..getResourceName(currentResource).."/"..script; local file = fileOpen(path); local content = fileRead(file,fileGetSize(file)); local f = loadstring(content) --setfenv(f,environment) pcall(f); fileClose(file); end; addEvent("onScriptLoadRequest",true); addEventHandler("onScriptLoadRequest",root,loadScript); function unloadScripts() environment = nil; currentResource = nil; dimension = nil; for _,v in pairs(arena.sounds) do stopSound(v); destroyElement(v); end; for _,v in pairs(arena.txds) do destroyElement(v); end; for _,v in pairs(arena.dffs) do engineRestoreModel(v); end; for _,v in pairs(arena.cols) do engineRestoreCOL(v); end; for _,v in pairs(arena.markers) do destroyElement(v) end; for _,v in pairs(arena.objects) do destroyElement(v); end; for _,v in pairs(arena.vehicles) do destroyElement(v); end; for _,v in pairs(arena.peds) do destroyElement(v); end; for _,v in pairs(arena.handlers) do removeEventHandler(v[1],v[2],v[3]); end; for _,v in pairs(arena.binds) do unbindKey(v[1],v[2],v[3]); end; for _,v in pairs(arena.commands) do removeCommandHandler(v[1],v[2]); end; setWaterLevel(0) resetSkyGradient() resetWaterColor() resetWaterLevel() setWaveHeight(0) resetHeatHaze() resetWindVelocity() resetAmbientSounds() resetWorldSounds() resetRainLevel() resetSunSize() resetSunColor() resetFogDistance() resetFarClipDistance() setGravity(0.008) setGameSpeed(1) setCloudsEnabled(false) arena = { sounds = {}; -- done dffs = {}; -- done txds = {}; -- done cols = {}; -- done objects = {}; -- done markers = {}; -- done vehicles = {}; -- done peds = {}; -- done handlers = {}; -- done binds = {}; commands = {}; }; _outputChatBox("onScriptUnloadRequest") end; addEvent("onScriptUnloadRequest",true); addEventHandler("onScriptUnloadRequest",root,unloadScripts); addEventHandler("onClientResourceStop",resourceRoot,unloadScripts); Link to comment
novo Posted July 24, 2015 Share Posted July 24, 2015 I guess that your issue might be caused by the fact that you are using addEventHandler when adding your custom events - onScriptLoadRequest, onScriptUnloadRequest. Another reason to use an environment instead. So yeah, either use the wrapper instead (_addEventHandler) or start with the environment thingy. Link to comment
John Smith Posted July 24, 2015 Author Share Posted July 24, 2015 Oh wow haha thanks man i didn't even see that mistake by the way, i'm guessing that in certain environment all functions have to be defined by the coder so, you're recommending this so that scripts can execute only the functions that i've coded into the enviorment or? btw it would be something like this? local environment = { -- example of environment print = print; outputChatBox = outputChatBox; }; Link to comment
novo Posted July 24, 2015 Share Posted July 24, 2015 Yeah that's it though I'd do the following: local loader = {environment = {}} function loader:generate_environment () self.environment = _G -- make so that it contains all mta functions, would be a mess to add them all on your own self.environment.outputChatBox = function() end self.environment.addEventHandler = function(name, element, func) -- (...) end -- or either / will not work self.environment = { outputChatBox = function() end, addEventHandler = function() end, triggerServerEvent = function() end, -- avoid server events triggering -- or either triggerServerEvent = function(name, element, ...) return triggerEvent(localPlayer, name, localPlayer, ...) end, -- redirect it towards the client itself } for k, v in pairs(_G) do if k ~= "loader" then -- our loader's 'global'-'environment' self.environment[k] = v end end end Just realized that doing it the second way is not really possible as the for loop would be overwriting your functions. You can instead, would be foolish though, place your functions into another table and then set your environment equal to _G and use a for loop with your functions' table this time instead. However, go through the first way. You can then simply execute generate_environment each time you want to reset/restart it after, of course, removing and destroying all unnecessary stuff. Link to comment
John Smith Posted July 24, 2015 Author Share Posted July 24, 2015 Okay thanks, but what would exactly be the security issues when not using an environment? edit: hi, im running into problems again it fails to open files (loadScript function) even though the filepath is correct... it just says that fileOpen is unable to load file :resourcename/client.lua for example am i doing something wrong? Link to comment
novo Posted July 25, 2015 Share Posted July 25, 2015 Well, you can this way avoid loaded scripts from executing your actual wrappered functions. Which means that if you have set a wrapper to _triggerServerEvent and not using an environment, it can be called from inside the loaded script. And you are avoiding this by using an own environment. Link to comment
John Smith Posted July 25, 2015 Author Share Posted July 25, 2015 ok thanks, but do you know what could be the issue of my overrider now not loading scripts? i mean it can load scripts from 2 maps but when i add new maps, it doesn't load scripts because fileOpen says unable to load file 'path' and the path is correct e.g 'fileOpen' could not open ':resourcename/client.lua' Link to comment
novo Posted July 25, 2015 Share Posted July 25, 2015 Are those files even being written/created? I am not sure it is possible to actually write into a different resource location from where you are running the functions. Link to comment
John Smith Posted July 25, 2015 Author Share Posted July 25, 2015 to manipulate or retrieve data from another resource you just add ':' before resourceName and it's supposed to work fine i have tried everything, and i don't get it how this script loader works on 2 maps perfectly fine(unless map creator has bugs in his map scripts) and all other maps, nothing works here's a preview of the warning that i'm getting: I don't know why this is happening, usually it would happen(i think) if resource which im trying to access is not loaded but i really doubt that as my race gamemode starts map resource before it triggers custom script loading edit: i have tried manually opening the path with server side and client side, appears that on client side it's impossible to load resource files (how didn't i realise this before?) so i'm gonna test it out now, and thanks fellas for help edit2: that was the issue! Thanks guys, it works now and if i need help again i will write in here ^^ Link to comment
novo Posted July 25, 2015 Share Posted July 25, 2015 That is what I meant, you can not manipulate files outside a resource itself. Link to comment
John Smith Posted July 25, 2015 Author Share Posted July 25, 2015 That is what I meant, you can not manipulate files outside a resource itself. how did i read the scripts then? Link to comment
novo Posted July 25, 2015 Share Posted July 25, 2015 I do not know, you probably ran those resources before. Err.. either way I did not check it out for a long while, they probably implemented it - quite a big security hole though. Link to comment
Bonsai Posted July 26, 2015 Share Posted July 26, 2015 I didn't read all this, but this might be helpful. https://wiki.multitheftauto.com/wiki/Filepath "Note: Server side filepaths which refer to resources will work correctly even if the other resource is not running. However client side filepaths require the target resource to be running." Link to comment
GTX Posted July 26, 2015 Share Posted July 26, 2015 Bonsai is right. Open your files on server side, send them to client with latent function and then cache them. Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now