LUA help

In this forum you will find and post information regarding the modding of Star Wars Battlefront 2. DO NOT POST MOD IDEAS/REQUESTS.

Moderator: Moderators

Post Reply
User avatar
cbadal
Corporal
Corporal
Posts: 156
Joined: Sun Jan 18, 2015 5:23 pm
Projects :: SWBF2 XBOX Mod Environment
Games I'm Playing :: SW Battlefront 2
xbox live or psn: No gamertag set
Contact:

LUA help

Post by cbadal »

I'm working on an addon system for SWBFII consoles and have become stumped on an issue.
I have a function called 'ProcessAddons()'
Which checks if a addon file exists and then tries to read and run it.

I expected that each time I call 'ReadDataFile(addonFile)', that the script referred to as 'addon' would be replaced internally by the one in the latest lvl file.
But I am only seeing the code from the first addon be executed. I don't know why.
A solution is to name the scripts 'addon000', 'addon001' ... [Which is kinda lame, but it works.]
Anyone know of a 'less lame' way to make this work?

Code: Select all

function ProcessAddons()
	print("ProcessAddons: START ")
	local addonFile = ""
	for i=1,999, 1 do 
		addonFile = string.format("addon\\%03d\\addon.lvl", i)
		if( ScriptCB_IsFileExist(addonFile) == 1) then 
			print("adding: " .. addonFile )
			ReadDataFile(addonFile)
			ScriptCB_DoFile("addon")
			print("did file: " .. addonFile )
		end 
    end 
    print("ProcessAddons: DONE ")
end
There are 3 addons.lvl files at:
addon\001\addon.lvl > contents 1 script named 'addon' content => print("001")
addon\002\addon.lvl > contents 1 script named 'addon' content => print("002")
addon\003\addon.lvl > contents 1 script named 'addon' content => print("003")

------------- output --------------
ProcessAddons: START
adding: addon\001\addon.lvl
001
did file: addon\001\addon.lvl
adding: addon\002\addon.lvl
did file: addon\002\addon.lvl
adding: addon\003\addon.lvl
did file: addon\003\addon.lvl
ProcessAddons: DONE
-----------------------------------
MileHighGuy
Jedi
Jedi
Posts: 1194
Joined: Fri Dec 19, 2008 7:58 pm

Re: LUA help

Post by MileHighGuy »

I cant really think of anything... unless you have the user input a string to check for instead of some incremented number. But maybe you don't want the user to have to worry about that.
User avatar
Anakin
Master of the Force
Master of the Force
Posts: 4817
Joined: Sat Sep 19, 2009 11:37 am
Projects :: RC Side Mod - Remastered - SWBF3 Legacy
Location: Mos Espa (germany)

Re: LUA help

Post by Anakin »

The Problem is not the ReadDataFile but at ScriptCB_DoFile("addon"). Lua is lazy and so tracks the names of scripts it already executed. And if you ask for the same script twice it just ignores it, because it already handled that.

There are some possible soluions i can think of:
1) give unique names to the script inside addon.lvl
Like ...\addon\XXX\addon.lvl contains a script named addon_XXX.lua

2) The scripts executed need to be tracked somewhere. Like in _G or something like that. Findout about it and set it to nil every time you run the script with ScribtCB_DoFile("addon")

3) As far as i remember there are two lua functions to execute code DoFile and something else. The other one does always execute no matter if the file was handled prior. But i'm not sure about the name or if it was already part of lua 5.0.2 or if it was removed from the swbf2 lua 5.0.2 binary.


==EDIT==

the different functions are
require: keep track of what already was loaded
dofile: just loads a file always you call this

Looks like ScribtCB_DoFile() is actually a lua require. So try using dofile() instead of ScribtCB_DoFile()

==EDIT2==

If you have any further questions about lua stuff, feel free to ping me on the discord server. i'm more active there and i know a lot about lua stuff. I already tried to recompile the new and old binaries to replace the limit one in modtools (no success :cry: but anyway i leared a lot about this stuff)
User avatar
cbadal
Corporal
Corporal
Posts: 156
Joined: Sun Jan 18, 2015 5:23 pm
Projects :: SWBF2 XBOX Mod Environment
Games I'm Playing :: SW Battlefront 2
xbox live or psn: No gamertag set
Contact:

Re: LUA help

Post by cbadal »

When the Game processes the addons for the PC, this is the exact scenario though.
Each addon has an 'addme.script' file with 1 file in it named 'addme' (although we've found that the addme.script can actually be a renamed from a 'addme.lvl' file and contain multiple scripts and textures, which is a handy way to add icons for the menus to use).

Do you know how would the game get away with doing this for the 'addme'?

It does not appear that script references make their way to '_G'.
Here is an example of a printout of the contents of '_G' during the 'addme' execution:
https://github.com/BAD-AL/SWBF2_Xbox_mo ... _addme.txt

In this case there are only functions, tables, strings and booleans.
If scripts were attached to '_G', then we should see 'addme' and for sure 'shell_interface' present.
Sporadia
Corporal
Corporal
Posts: 151
Joined: Thu Jan 24, 2019 11:02 pm
Projects :: No Mod project currently
Games I'm Playing :: None
xbox live or psn: No gamertag set

Re: LUA help

Post by Sporadia »

Most of this is too complicated for me, but if you're looking for a list of loaded file names, what about the _LOADED table? Saw it in _G
Ronald79
Posts: 1
Joined: Sat Jan 23, 2021 6:59 am
Projects :: No Mod project currently.
Games I'm Playing :: Fifa
xbox live or psn: No gamertag set

Re: LUA help

Post by Ronald79 »

Sporadia wrote:
Sat Jan 23, 2021 4:58 am
Most of this is too complicated for me, but if you're looking for a list of loaded file names, what about the _LOADED table? Saw it in _G
Also for me
User avatar
Anakin
Master of the Force
Master of the Force
Posts: 4817
Joined: Sat Sep 19, 2009 11:37 am
Projects :: RC Side Mod - Remastered - SWBF3 Legacy
Location: Mos Espa (germany)

Re: LUA help

Post by Anakin »

cbadal wrote:
Fri Jan 22, 2021 6:52 pm
When the Game processes the addons for the PC, this is the exact scenario though.
Each addon has an 'addme.script' file with 1 file in it named 'addme' (although we've found that the addme.script can actually be a renamed from a 'addme.lvl' file and contain multiple scripts and textures, which is a handy way to add icons for the menus to use).

Do you know how would the game get away with doing this for the 'addme'?

It does not appear that script references make their way to '_G'.
Here is an example of a printout of the contents of '_G' during the 'addme' execution:
https://github.com/BAD-AL/SWBF2_Xbox_mo ... _addme.txt

In this case there are only functions, tables, strings and booleans.
If scripts were attached to '_G', then we should see 'addme' and for sure 'shell_interface' present.
Have you tried using the function dofile (https://github.com/BAD-AL/SWBF2_Xbox_mo ... .txt#L1059) instead of ScriptCB_DoFile (https://github.com/BAD-AL/SWBF2_Xbox_mo ... e.txt#L394) ?
Sporadia wrote:
Sat Jan 23, 2021 4:58 am
Most of this is too complicated for me, but if you're looking for a list of loaded file names, what about the _LOADED table? Saw it in _G
Very good point (https://github.com/BAD-AL/SWBF2_Xbox_mo ... .txt#L1918)


io table may be interesting too if it allows you to read/write stuff (https://github.com/BAD-AL/SWBF2_Xbox_mo ... .txt#L2144)
os can help too (https://github.com/BAD-AL/SWBF2_Xbox_mo ... .txt#L2188)

The PC version does not support those but maybe xbox/PS do?
User avatar
cbadal
Corporal
Corporal
Posts: 156
Joined: Sun Jan 18, 2015 5:23 pm
Projects :: SWBF2 XBOX Mod Environment
Games I'm Playing :: SW Battlefront 2
xbox live or psn: No gamertag set
Contact:

Re: LUA help

Post by cbadal »

Sporadia wrote:
Sat Jan 23, 2021 4:58 am
Most of this is too complicated for me, but if you're looking for a list of loaded file names, what about the _LOADED table? Saw it in _G
Ran the tests ( hooked up 'print statements' to go to the credits ) and found the following:

Code: Select all

_LOADED: {  },
os: { },
io: {stdin:userdata, stdout:userdata, stderr:userdata }
Looks like 'dofile()' crashes the calling script on PSP, as the script doesn't finish (on both valid and invalid filenames).
Sporadia
Corporal
Corporal
Posts: 151
Joined: Thu Jan 24, 2019 11:02 pm
Projects :: No Mod project currently
Games I'm Playing :: None
xbox live or psn: No gamertag set

Re: LUA help

Post by Sporadia »

I have another suggestion. What happens if you use dofile() or even ScriptCB_DoFile() on an addon.script instead of having addon.lvl? (Unless you're using .lvl because you need to on console). My idea is it could behave the same as addme.script based on the file extension. I don't see what else would distinguish your addon from an addme.

Edit: Although if you can do that, presumably you can repurpose your code to make addme files work? I don't know what the limits are on what consoles can do. Is .script off the table?

Edit 2 (this edit was based on a misunderstanding):
Hidden/Spoiler:
Also, has anyone tested _LOADED on PC, to see what it's supposed to contain? If that's empty too then there might not even be a table of script references, because the majority of tables in _G can be ruled out, and there'd only be a few left to check like coroutine (at this point picking out tables with names that I don't understand). The only other weird thing is that _G lists the table _G, which I assume is a reference to itself but if you're already reading _G you know it exists so there's no reason to list it. It looks like _G contains every important table without missing any, so if a table of script references isn't in there then it probably doesn't exist.
Last edited by Sporadia on Sun Jan 24, 2021 9:54 am, edited 2 times in total.
User avatar
Anakin
Master of the Force
Master of the Force
Posts: 4817
Joined: Sat Sep 19, 2009 11:37 am
Projects :: RC Side Mod - Remastered - SWBF3 Legacy
Location: Mos Espa (germany)

Re: LUA help

Post by Anakin »

_loaded is empty on PC, too.

==EDIT==

Code: Select all

tprint(_G._LOADED)

ReadDataFile("..\\..\\addon\\XXX\\printLVL.lvl")

tprint(_G._LOADED)

print("marker 1")
ScriptCB_DoFile("printLVL")

tprint(_G._LOADED)


print("marker 2")
ScriptCB_DoFile("printLVL")

tprint(_G._LOADED)

print("marker 3")
dofile("..\\..\\addon\\XXX\\printLVL.lvl")

tprint(_G._LOADED)

print("marker 4")
dofile("..\\..\\addon\\XXX\\printLVL.lvl")

tprint(_G._LOADED)

Code: Select all

XXX_interface_script: entered
table: 07B5730C {
}
table: 07B5730C {
}
marker 1
Hello There World
table: 07B5730C {
}
marker 2
table: 07B5730C {
}
marker 3
cannot read ..\..\addon\XXX\printLVL.lvl: No such file or directory
looks like dofile points somewhere else then the default ScriptCB_DoFile


==EDIT2==

Ok, found out how it works. you need uncompiled lua files for dofile:

Code: Select all

tprint(_G._LOADED)

ReadDataFile("..\\..\\addon\\XXX\\printLVL.lvl")

tprint(_G._LOADED)

print("marker 1")
ScriptCB_DoFile("printLVL")

tprint(_G._LOADED)


print("marker 2")
ScriptCB_DoFile("printLVL")

tprint(_G._LOADED)

print("marker 3")
dofile("addon\\XXX\\printLVL.lua")

tprint(_G._LOADED)

print("marker 4")
dofile("addon\\XXX\\printLVL.lua")

tprint(_G._LOADED)

Code: Select all

XXX_interface_script: entered
table: 07A4130C {
}
table: 07A4130C {
}
marker 1
Hello There World
table: 07A4130C {
}
marker 2
table: 07A4130C {
}
marker 3
Hello There World
table: 07A4130C {
}
marker 4
Hello There World
table: 07A4130C {
}
Sporadia
Corporal
Corporal
Posts: 151
Joined: Thu Jan 24, 2019 11:02 pm
Projects :: No Mod project currently
Games I'm Playing :: None
xbox live or psn: No gamertag set

Re: LUA help

Post by Sporadia »

Oh I've just understood how the _G was printed in the doc. I thought it was a table that contained strings but I've just understood that it's an object with all it's operations printed out. So if _LOADED is an operation of the object _G (along with all those other tables), it means there is a second _G table contained inside the object _G. What's in _G._G?
Edit: Phrased this more properly.

Edit 2: Also I don't understand tprint exactly but those hex numbers look like addresses, like what you get when you try to print a nested table. What happens if you replace each of your print tests with this:

Code: Select all

for index, table in ipairs(_G._LOADED) do
    print(index)
    tprint(table)
end
User avatar
cbadal
Corporal
Corporal
Posts: 156
Joined: Sun Jan 18, 2015 5:23 pm
Projects :: SWBF2 XBOX Mod Environment
Games I'm Playing :: SW Battlefront 2
xbox live or psn: No gamertag set
Contact:

Re: LUA help

Post by cbadal »

Forgot to post my 'dumpToString' function (used to print table data):

Code: Select all

function dumpToString(obj, count)
    if( count == nil ) then count = 0 end 
    if type(obj) == 'table' then
        local retVal =  string.rep('  ', count) .. '{ '
        for k,v in pairs(obj) do
            retVal =  retVal ..  tostring(k) .. ':' .. dumpToString(v, count+1) .. ', '
        end
        return retVal .. ' },'
    elseif type(obj) == 'string' then 
        return '"' ..  tostring(obj) .. '"'
    else 
        return tostring(obj) 
    end
end
Also, I think this is the code is what I used to print the Global environment.

Code: Select all

function dump(obj)
	if type(obj) == 'table' then
		for k,v in pairs(obj) do
			print( type(v)..':'..tostring(k)) 
		end
	else
		print( type(v) ..': ' .. tostring(obj))
	end
end
dump(_G)
And yes 'dofile()' references files from the program's filesystem location (GameData) and 'ReadDataFile()' reference root is '_LVL_PC' (or _LVL_XBOX, _LVL_PSP, _LVL_PS2).
Reading the file in as as a '.script' does not change the behavior.
User avatar
Anakin
Master of the Force
Master of the Force
Posts: 4817
Joined: Sat Sep 19, 2009 11:37 am
Projects :: RC Side Mod - Remastered - SWBF3 Legacy
Location: Mos Espa (germany)

Re: LUA help

Post by Anakin »

Sporadia wrote:
Sun Jan 24, 2021 9:49 am
Oh I've just understood how the _G was printed in the doc. I thought it was a table that contained strings but I've just understood that it's an object with all it's operations printed out. So if _LOADED is an operation of the object _G (along with all those other tables), it means there is a second _G table contained inside the object _G. What's in _G._G?
Edit: Phrased this more properly.

Edit 2: Also I don't understand tprint exactly but those hex numbers look like addresses, like what you get when you try to print a nested table. What happens if you replace each of your print tests with this:

Code: Select all

for index, table in ipairs(_G._LOADED) do
    print(index)
    tprint(table)
end
_G is a lua specific global variable that contains EVERYTHING. Every function, every table, every variable. In case you are in a scope, but you want to access a variable from a different scope you can do it through _G. So since _G is a valid global variable it's of course part of _G, too. You could do _G._G._G and it's the same as _G.
tprint is a help function to print out table content with all names, values and their datatype. It's pretty much the same as uf_print() from Zerted but adjusted by marth, so i can collapse the content in my debug log.

Yes the number is a memory address since every element is printed out by it's type, name and value. The value of a table is a memory pointer. The following {} block contains everything that is in there. Just in case you wanna test this on _G it won't work and crash the game. Use uf_print() without deep search activated instead.

if you're interested in the code, here it is:

Code: Select all

function getn(v)
    local v_type = type(v);
    if v_type == "table" then
        return table.getn(v);
    elseif v_type == "string" then
        return string.len(v);
    else
        return;
    end
end

function string.starts(str, Start)
    return string.sub(str, 1, getn(Start)) == Start;
end

function tprint(t, indent)
    if not indent then indent = 1, print(tostring(t) .. " {") end
    if t then
        for key,value in pairs(t) do
            if not string.starts(tostring(key), "__") then
                local formatting = string.rep("    ", indent) .. tostring(key) .. ": ";
                if value and type(value) == "table" then
					print(formatting .. tostring(value) .. " {")
                    tprint(value, indent+1);
				else
					print(formatting .. tostring(value))
                end
            end
        end
		print(string.rep("    ", indent - 1) .. "}")
    end
end


-- helper function from Zerted to print all contents of a table
function uf_print( data, nested, depth )
	if (not data) then return end	--must have something to print
	if (not type) then return end	--must have something to print
	if depth == 0 then
		print(depth..": uf_print(): Starting: ", data, type, nested, depth)
	end

	--for each pair in the given table, 
	for key,value in pairs(data) do

		--check for nils
		if key == nil and value == nil then
			print(depth..": uf_print(): Both the key and value are nil")
		elseif key == nil then
			print(depth..": uf_print(): Nil key, but value is:", value)
		elseif value == nil then
			print(depth..": uf_print(): Nil value, but key is:", key)
		else
			--have no nils (but a continue keyword would have been nice...)
			
			--display the key, value pair if possible
			if key ~= "mapluafile" then
				--normal display
				print(depth..": Key, Value: ", key, value)
			else
				--have to format map lua file values to prevent crash when outputting the value
				local map = string.format(value, "<A>", "<B>")
				print(depth..": Key, Formated Value: ", key, map)
			end
	
			--if nested, search deeper, but don't recurse into the global table or our starting table
			if nested and key ~= "_G" and key ~= data then
			
				--the developers didn't include type(), so have to use this hack to determine if the value represents a table
				local result = pcall(function(array)
					table.getn(array)
				end, value)
				
				--can only process tables
				if result then
					uf_print(value, nested, depth+1)
				end
			end
		end
	end
	
	if depth == 0 then
		print(depth..": uf_print(): Finished: ", data, nested, depth)
	else
		print()
	end
end

@cbadal: does it work if you use a lua file instead of a lvl with dofile?
User avatar
cbadal
Corporal
Corporal
Posts: 156
Joined: Sun Jan 18, 2015 5:23 pm
Projects :: SWBF2 XBOX Mod Environment
Games I'm Playing :: SW Battlefront 2
xbox live or psn: No gamertag set
Contact:

Re: LUA help

Post by cbadal »

I was trying with a .lua file.
I would be pretty surprised if dofile worked on a .script file.
Post Reply