Author Topic: conventions for script organization and modularization  (Read 1882 times)

0 Members and 1 Guest are viewing this topic.

Offline Nuke

  • Ka-Boom!
  • 212
  • Mutants Worship Me
conventions for script organization and modularization
the purpose of this thread is to discuss means of script organization and modularization. when making large scripts it is sometimes necessary to break the project down to manageable chunks for faster and more organized development. also it helps to make your script modular so that systems coded for previous projects can be reused and refined. freespace does not always give you all the facilities you need to accomplish these tasks, but i find lua usually does, and thats what this thread is about.

for my first example i posted this code to the scp forum, and thought it should also have a presence here. it lets you find and load script files using cfile, and then allows you to execute that script as if it were a function. this is very useful for letting you load external libraries in other mod folders. it could probibly also be used for organizational purposes, though im not sure about performance at this point. il quote my post from the scp board:

k i think i figured out how to load "libraries" without having to know of an exact location of the lua files. this  replaces dofile() calls, which needs to know the way from root to where the files are in the mod dirs. it does this by using the cfile facilities to locate and open files independently of any known path. so essentially i load the lua code into a string. i then use loadstring to turn it into a lua chunk (which is essentially a code block). loadstring then returns a function that runs the block when called. to make things a little faster i made it so it only needs to read the file once, to generate the chunk function, and then it caches it into a table for later use.

i put the function at the head of the global init hook. i figure i can use it to chop up my script into manageable pieces and make things somewhat more modular, though its main purpose is to load libraries. id rather the scripting table had better facilities to load multiple files per hook. but this is a good interim solution. im still kind of concerned about cheating though. im not sure if script ran in this manor would get past anti-cheating checks if it were modified. i would assume those checks only apply to what is in the scripting.tbl and not lua files loaded by the table (and likewise lua files loaded by other lua files). something to think about anyway.

Code: [Select]
--function to load and run lua files
--takes string filename and boolean cacheonly
--cfile will try to find filename in all accesible locations and load it only if it hasnt done so already
--if cacheonly flag is set, code will be cached but not executed, good for inits. however it is ignored when calling an already cached chunk.
--returns true on success, false on failure to compile, or nil on failure to find/load file
chunck_cache = {}
function execute_lua_file(filename, cacheonly)
--dont reload chunks from file if they have already been loaded. because faster == badass
if chunck_cache[filename] then
chunck_cache[filename]()
return true
else
if cf.fileExists(filename, "", true) then
--open the file
local file = cf.openFile(filename, "r", "")
local fstring = file:read("*a") --load it all into a string
file:close()
if type(fstring) == "string" then
--use the string as a code chunk and convert it to function
local func, errorstring = loadstring(fstring, filename)
if type(func) == "function" then
--cache function
chunck_cache[filename] = func
--maybe execute
if not cacheonly then
chunck_cache[filename]()
end
return true
--compile error
elseif errorstring then
ba.warning("Error in '"..filename.."': "..errorstring)
return false
end
end
else --file not found error
ba.warning("File '"..filename.."' not found")
return nil
end
end
end

--call lua from file or chunk cache if file has already been loaded
execute_lua_file("somefile.lua")

--precache lua file for later execution
execute_lua_file("somefile.lua", true)


*edit new version of script added*
« Last Edit: February 14, 2011, 11:07:59 am by Nuke »
I can no longer sit back and allow communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy to sap and impurify all of our precious bodily fluids.

Nuke's Scripting SVN

 

Offline m!m

  • 211
Re: conventions for script organization and modularization
Nice thing but I think that "chunck_cache["filename"]" should be replaced by "chunck_cache[filename]" because else it will only use the string "filename" as key thus overwriting any previous functions (please correct me if I'm wrong :nervous:.). Also loadstring returns an error message as a second value if the compilation fails so you could also show that in an error message.
Overall, this should be very helpful in scripting  :) :yes:

 

Offline Nuke

  • Ka-Boom!
  • 212
  • Mutants Worship Me
Re: conventions for script organization and modularization
oops, forgot about that. my lua-fu is getting rusty. script updated.
« Last Edit: February 14, 2011, 11:08:12 am by Nuke »
I can no longer sit back and allow communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy to sap and impurify all of our precious bodily fluids.

Nuke's Scripting SVN

 

Offline Nuke

  • Ka-Boom!
  • 212
  • Mutants Worship Me
Re: conventions for script organization and modularization
so i was applying this function to all the scripts where i had used dofile in the past. i find that it has the added bonus of being able to treat scripting libraries as mods and less like some random directory in the fs2 dir. so far ive been treating libraries mostly as stacks of lua files (stored in /libname/data/scripts) and no tables or other data, though it would be possible to include graphics and model data, such as bitmaps for a scripted gui. i think its somewhat of a good practice to omit any tables, and only include assets used by the scripting library directly.

scripting libraries themselves could be organized. using the function above in the main lua file of the library, you could run other files in the library in any particular order. going back to my gui system, this is useful, since i could have a lua file for each interface type the system would use. making libraries very easy to work with.

furthermore you could, with a minor tweak to a mod.ini file, keep local, most up to date libraries in a central location, and known compatible libraries locally in the working mod folder, allowing quick packaging of the mod for release as well as commit with svn. so i think i can say for now that this little piece of script can be very powerful indeed.
I can no longer sit back and allow communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy to sap and impurify all of our precious bodily fluids.

Nuke's Scripting SVN