1 2 3 4
8 9
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
Thanks. But I feel like this does not solve my problem much... I can shorten my 150 lines of code to 15, but will have to either a) introduce a table like you said but other functions will have to access it every frame. I feel like accessing a table by key string is much costlier than accessing a variable itself. or b) save a table but then go through that table to assign values to the stand alone variables anyway (so I would shorten my code but then lengthen it again). If you need an example of my code:
for line in settings:lines() do  -- finding the settings and assigning them to variables
			
			-- bools:
			if string.find(line,"BoolBrosPath") then 
				substringStart=string.find(line,"%:")+2
				substringEnd=string.len(line)
				substring=string.sub(line,substringStart,substrEnd)
				setting=toboolean(substring)
				
				if setting == nil then
					BoolBrosPath = GLOBALSETTINGS["BoolBrosPath"]
				else
					BoolBrosPath = setting
				end
				
			elseif string.find(line,"BoolNotifications") then 
				substringStart=string.find(line,"%:")+2
				substringEnd=string.len(line)
				substring=string.sub(line,substringStart,substrEnd)
				setting=toboolean(substring)
				
				if setting == nil then
					BoolNotifications = GLOBALSETTINGS["BoolNotifications"]
				else
					BoolNotifications = setting
				end
			
			elseif string.find(line,"BoolWarnings") then 
				substringStart=string.find(line,"%:")+2
				substringEnd=string.len(line)
				substring=string.sub(line,substringStart,substrEnd)
				setting=toboolean(substring)
				
				if setting == nil then
					BoolWarnings = GLOBALSETTINGS["BoolWarnings"]
				else
					BoolWarnings = setting
				end
				
			elseif ........

I can make a table like you said but then I would have to change this
...
while true do
...
if BoolBrosPath then drawBrosPath() end
...
into
...
while true do
...
if a["BoolBrosPath"] then drawBrosPath() end
...
so as said I'm worried if this causes a slowdown. Maybe if I use numbers, but then it gets confusing :)
Player (74)
Joined: 8/26/2015
Posts: 70
It will be slower, but only by a constant factor, and that should be a small factor at that. I can't imagine Lua taking more than a couple of indirections to access a table value, so it should still be fine in terms of performance*. Plus, you're already doing a suboptimal (but definitely good enough) string.find which is way more costly than swapping variables to table values. I personally think parsing the entire text into a settings table would be better, but up to you of course! * As always, you never know exactly how it will perform until you actually test performance yourself.
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
The first code in my previous post is part of function GuiLoadSettings() and it occurs only once when you load the script. Doing expensive operations on a one time instance is ok. But the 2nd/3rd code runs every frame. And since you said doing a["string"] is slower, I will not go for it. The only way I see how I can do it is to change all the variables into numbers, so BoolBrosPath becomes value in a table for key "1", BoolNotifications becomes "2" etc. But then the code becomes highly confusing. So not going for that either. I think...
local SettingsTable={
[1]=false, -- BoolBrosPath
[2]=false, -- BoolNotifications
...}
^ Is that what you meant parsing it into a setting table? Thanks for the help so far
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
MUGG wrote:
The only way I see how I can do it is to change all the variables into numbers, so BoolBrosPath becomes value in a table for key "1", BoolNotifications becomes "2" etc. But then the code becomes highly confusing.
Constants then?
Editor, Emulator Coder
Joined: 8/7/2008
Posts: 1156
Mugg, the speed of lua itself is not going to be a significant consideration for you, now that i've seen how slow it is just to make one call into the emulator. There's nothing to worry about unless youre doing serious number crunching in lua.
Player (74)
Joined: 8/26/2015
Posts: 70
Overall, my point is that at the level you're doing things, small cost increases don't matter. Sure, it's slightly slower, but the win in being easier to read is way more valuable, at least to me. The expensive bits are going to be cross-language calls, and big calculations, e.g. with nested for loops (quadratic time complexity, etc)
MUGG wrote:
The first code in my previous post is part of function GuiLoadSettings() and it occurs only once when you load the script. Doing expensive operations on a one time instance is ok. But the 2nd/3rd code runs every frame. And since you said doing a["string"] is slower, I will not go for it.
Alright, I'll change my argument: drawBrosPath() is going to be much slower than the difference between a["var"] and var, so much that the latter change will be negligible.
MUGG wrote:
The only way I see how I can do it is to change all the variables into numbers, so BoolBrosPath becomes value in a table for key "1", BoolNotifications becomes "2" etc. But then the code becomes highly confusing. So not going for that either. I think...
Doing this has the same (or very similar) cost, as it still is a level of indirection on a table, but is harder to read. I'd really recommend not doing that.
MUGG wrote:
local SettingsTable={
[1]=false, -- BoolBrosPath
[2]=false, -- BoolNotifications
...}
^ Is that what you meant parsing it into a setting table? Thanks for the help so far
For the settings table, yes, but I meant still with string keys - as I said above, the cost of string key to integer key is comparable. Once again, I'd like to emphasise: you don't need to worry about microoptimisations in performance like this. Write it the way that is easy to read, understandable, and in a way that expresses your intention, then if it's too slow THEN worry about optimising. And even then, you should be looking at inner loops, etc, before getting all the way down to an extra indirection level for a few variable accesses.
Amaraticando
It/Its
Editor, Player (158)
Joined: 1/10/2012
Posts: 673
Location: Brazil
EDIT: Table and string creation every frame can slowdown things. Table access, no matter the type of the key entry, is pretty optimized. Every local variable is internally stored in a table anyway, so you don't need to worry about it.
Editor, Emulator Coder
Joined: 8/7/2008
Posts: 1156
local variables arent stored in tables. that's why writing "local" all the time is the #1 top lua performance tip.
Amaraticando
It/Its
Editor, Player (158)
Joined: 1/10/2012
Posts: 673
Location: Brazil
Sorry for the confusion, you were right. Global variables are stored in _G and are slower. Tables are slightly faster in the array part, if compared to the hash part. Anything that's not [1, n] (i.e., outside the reach of ipairs) will be hashed. But I don't think it's a nice idea to optimize this at the cost of a dirty code. Little experiment: without this Lua script, I get 67-70 fps (SNEShawk). With it, the fps drops to 62-65, which is really small after 10 thousand loops per frame.
Language: Lua

local tab = {entry = "value"} local val while true do for i = 1, 10000 do val = tab.entry end gui.text(0, 80, val) emu.frameadvance() end
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
Ok, I have run a few tests myself and you have also convinved me. So I'm making the Settings table now as AdituV suggested. I'm getting a little confused about usage of "local" so: What's the best choice of these three, assuming "var" is only needed inside the function? a)
Language: Lua

local var local function=test() var=memory.read_s8(0x1234) end while true do test() emu.frameadvance() end
b)
Language: Lua

local function=test() var=memory.read_s8(0x1234) end while true do test() emu.frameadvance() end
c)
Language: Lua

local function=test() local var=memory.read_s8(0x1234) end while true do test() emu.frameadvance() end
Is there a difference between b) and c)?
Noxxa
They/Them
Moderator, Expert player (4141)
Joined: 8/14/2009
Posts: 4083
Location: The Netherlands
Relevant doc: http://lua-users.org/wiki/ScopeTutorial In general, it's nearly always best to scope the variable to only the area where it's needed (so use local variables whenever possible). It doesn't matter in terms of speed or performance, but it ensures that your variable will not conflict with other variables with the same name, which can potentially save you a lot of headaches when trying to debug code if you are inadvertently changing around the same variable all over the place. Locally scoped variables allow you to use common-name variables (like "x", "y", or "i") repeatedly in different contexts without these different variables interfering which each other. Even if you think it is most likely not going to become a problem, it's still just good form and just a little bit of extra safety. tl;dr: Use C.
http://www.youtube.com/Noxxa <dwangoAC> This is a TAS (...). Not suitable for all audiences. May cause undesirable side-effects. May contain emulator abuse. Emulator may be abusive. This product contains glitches known to the state of California to cause egg defects. <Masterjun> I'm just a guy arranging bits in a sequence which could potentially amuse other people looking at these bits <adelikat> In Oregon Trail, I sacrificed my own family to save time. In Star trek, I killed helpless comrades in escape pods to save time. Here, I kill my allies to save time. I think I need help.
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
Assuming there is an address (1 byte), what lua code can I use to check what bits are 1 and 0? I would like to 'iterate' through the byte and do something depending if the given bit is 1 or 0. Also, what code can I use to set a certain bit in an address (1byte) to 1 or 0?
Amaraticando
It/Its
Editor, Player (158)
Joined: 1/10/2012
Posts: 673
Location: Brazil
To see:
Language: lua

value = 0x96 -- 10010110 for bitnum = 0, 7 do if bit.check(value, bitnum) then some_action() end end
To set: uint32 bit.set(uint num, int pos) Sets the bit 'pos' in 'num' Edit: typo
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
Amaraticando wrote:
I make like this:
Language: Lua

while true do --- code -- Frame advance: hack for performance if client.ispaused() then emu.yield() gui.clearGraphics() gui.cleartext() else emu.frameadvance() end end
So I have to admit, I didn't get this to work back in 1.11.3 and I can't get it to work in 1.11.6 now. When the emu is paused, the script seems to be running (it responds to clicks) but I can't see anything because the screen is not updated. I would be glad if you or someone else could try to get it to work on my script. http://pastebin.com/raw/QNzAjjKQ I already put your code in. I deleted some of my code for more clarity.
Editor, Emulator Coder
Joined: 8/7/2008
Posts: 1156
Try dragging other windows in front of bizhawk or dragging it off your screen. A long time ago there was code in my way that would make the screen get re-drawn when there was no emulation going on, and I deleted it. Maybe it's time to fix that.
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
When I do that, it still shows the same paused screen and doesn't update. I thought maybe my script depended too much on emu.framecount() but I more or less confirmed now that that's not the problem.
Amaraticando
It/Its
Editor, Player (158)
Joined: 1/10/2012
Posts: 673
Location: Brazil
MUGG wrote:
When I do that, it still shows the same paused screen and doesn't update. I thought maybe my script depended too much on emu.framecount() but I more or less confirmed now that that's not the problem.
For me, only gui.text is updated. Any other drawing that relies on the game surface/scaling will not be updated .by emu.yield(). Maybe you'll want to use void gui.DrawNew(string name), but the last time I checked, this is very slow.
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
gui.text is updating for me too. But gui.drawtext, gui.drawbox, etc. aren't. It looks like gui.DrawNew("emu") does what I want. My script is running perfectly while emu is paused. Thanks!
   if client.ispaused() then
		gui.DrawNew("emu")
        emu.yield()
	else
		emu.frameadvance()
	end
Amaraticando
It/Its
Editor, Player (158)
Joined: 1/10/2012
Posts: 673
Location: Brazil
Hum, I told you that gui.DrawNew was slow as hell, but it seems decent now, at least on Direct3D9. This model seems useable now: http://pastebin.com/zrkuPZWw
Post subject: A nil value?
Joined: 10/23/2009
Posts: 545
Location: Where?
Hello, I apparently have a nul value at the line before the last line of the following code:
Language: lua

if mainmemory.read_s32_le(0x16C8) == 912 then gui.pixelText(10,10,"speX:" .. mainmemory.read_s32_le(0x16C8)) --Display a green speed, meaning that I'm at top speed else gui.pixelText(10,10,"speX:" .. maimmemory.read_s32_le(0x16C8)) end
But I'm baffled, it doesn't throw an error on the third line. I seem to have written exactly the same thing.(Colors are yet to be added). So I can't figure out what is wrong. The rest of the code is just gui.drawtexts, so it shouldn't interfere with that poriton of the code.
Post subject: Re: A nil value?
Amaraticando
It/Its
Editor, Player (158)
Joined: 1/10/2012
Posts: 673
Location: Brazil
niamek wrote:
Hello, I apparently have a nul value at the line before the last line of the following code:
Language: lua

if mainmemory.read_s32_le(0x16C8) == 912 then gui.pixelText(10,10,"speX:" .. mainmemory.read_s32_le(0x16C8)) --Display a green speed, meaning that I'm at top speed else gui.pixelText(10,10,"speX:" .. maimmemory.read_s32_le(0x16C8)) end
It's a minor typo: maimmemory.read_s32_le(0x16C8) -> mainmemory.read_s32_le(0x16C8)
Joined: 10/23/2009
Posts: 545
Location: Where?
Ohh wow, I totally missed that. I expected that typo like that wouldn't give a nil value. Thank you! So now I tried with colors. Having don some scripting with VBA, I recalled that writting green or blue would work. So I did this:
Language: lua

if mainmemory.read_s32_le(0x16C8) == 912 then gui.pixelText(5,21,"speX:" .. mainmemory.read_s32_le(0x16C8),green) -- elseif -- mainmemory.read_s32_le(0x16C8) == 0 then -- gui.pixelText(5,21,"speX:" .. mainmemory.read_s32_le(0x16C8)) else gui.pixelText(5,21,"speX:" .. mainmemory.read_s32_le(0x16C8),blue) end
But it doesn't seem to put any blue or green. So I'm missing something. Do I have to put colors in hexadecimal format? (The commented lines are lines that I wrote, but not ready to test that line. Basically, i wanted a color for 0, a color for 912, and one another color for any other value.) So here is the function.
Language: lua

gui.drawText(int x, int y, string message, [Color? forecolor = null], [Color? backcolor = null], [int? fontsize = null], [string fontfamily = null], [string fontstyle = null])
As I was told, [] mean not mandatory. So if i put only one color(Like I did), it will be for the forecolor? Or both? Or neither? I don't plan to mess with fonts.
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
Put color names as string, or use 0x00000000 hex format. Transparency Red Green Blue.
Language: Lua

local col=nil local speX=nil while true do speX=mainmemory.read_s32_le(0x16C8) if speX == 912 then col="green" else col="blue" end gui.pixelText(5,21,"speX:" .. speX,col) emu.frameadvance() end
Joined: 10/23/2009
Posts: 545
Location: Where?
I'd rather use a hex format since it gives me more choice of colors.Thank you Mugg! Something is really wrong with my calculus.
Language: lua

speedvariation= 912 - mainmemory.read_s32_le(0x16C8) diff= 255/speedvariation
This shouldn't give a very small value such as 0,2. I expectedit to be much higher like 107. The mainmemory.read_s32_le(0x16C8) can be 384. From my calculator, I should have something like 107. Not 0,483. It's because I can lose some speed at some point. And I figured that I will calculate the frames needed so that the speed variation will lose a whole frame when compared to the max speed. I canc onfirm I have the good address. I checked on http://www.lua.org/pil/3.1.html and the operator for dividing something is the right one. So I'm at a lost. The substraction works, the division works. But the division with a real value like 5 works. So I tried with
Language: lua

diff = 255/ (912 - mainmemory.read_s32_le(0x16C8))
But it still gives a too low value. I'm really confused...
EDIT: Scrap that. Miscalculated.[/b]
Editor, Expert player (2315)
Joined: 5/15/2007
Posts: 3856
Location: Germany
FractalFusion wrote:
MUGG wrote:
Well, there doesn't seem to be a hook for the X or minimize buttons. When clicking X, var doesn't become nil but the form window is gone. How am I supposed to detect that the window has gone if all I have is the var variable?
A useful piece of code from Amaraticando's Super Mario World script:
event.unregisterbyname("exit")
event.onexit(function()
    local destroyed = forms.destroy(var)
    client.paint()
end, "exit")
There isn't a hook for X. So the next best thing is not to depend on the user clicking X. Destroy the form when the user closes or reloads the script. This also prevents handle overload crashes that occasionally happen when you don't do this.
I was already doing forms.destroyall when script is ended. I take it it's still not possible to work around this? When user clicks "Close", I can run:
	if EditStatsFormWindow~=nil then
		forms.destroy(EditStatsFormWindow)
		EditStatsFormWindow=nil
	end
but I don't know how I can make this code run when user clicks "x".
1 2 3 4
8 9