Jump to content

unloading code which was loaded with loadstring


Recommended Posts

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

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

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

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

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

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

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 :D

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
_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

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

Oh wow haha thanks man i didn't even see that mistake :D

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

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

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

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

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

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:

errorz.PNG

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

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...