As shown in the picture above, the "from" variable is being considered a function at some time during execution. Problem is: there's nowhere in the program that I can turn that variable into a function, because it is a local variable (and the only place the 2nd argument is ever assigned is in the function itself):
function unpack(list,from,to) from,to=from or 1,to or #list if from<=to then return list[from],unpack(list,from+1,to) end end |
function to_tab_unp(tab) return unpack(str_to_table(tab)) end |
The weirdest thing is that I call the line "in cr_char line 5 (tab 2)" every time I create a character. In this particular instance I'm recreating battles to get until I get one with a formation that fits the difficulty level I want. So it's like 1/10000 of cases generates that error. But the table being unpacked is always the same:
to_tab_unp(",{,{,{,{,,f,{,,,{,{,,,{,{,{,{,{,,,,") |
So it seems to me that this is a pico-8 bug, because the function is always exactly the same but and the error pops for no apparent reason...?
Thoughts?
Avoid using keywords for variable names. I've run into this problem as well. Watch as you type a variable name and if any part of it turns pink or green while typing, choose a different variable name instead.
I can't post the cart without minifying it, so here's the code if needed:
Tab 0
Tab 1
Tab 2
Tab 3
Tab 4
Tab 5
Tab 6
@dw817 the variables "to" and "from" have normal gray color. I tried changing the names, but got the same problem:
Post entire code please, BoneVolt, where error occurs, and I'll see if I can find what is causing it - and a remedy.
Not related pbly but you are setting i=j in the str_to_tqb function.
This is actually a no-op as the for loop will reset i (unlike say, c/c++ for loops)
To reproduce, suggest to create a simple cart that does this decoding in a loop.
@dw817 I posted the entire code above, separated by tabs so it's easier to know which lines are being cited in the error message.
@freds72 I didn't know that, thanks for the info! (yeah, I probably did that at some point in C++ and assumed it would be the same here)
I tried to reproduce it in a small cart yesterday, but it doesn't reproduce the error... It also only happens on that particular string.
I tried to reproduce again now by making a bare bones version of the game one with the same strings and it also doesn't repeat the error (I kept it running for 10 minutes... the error usually pops up in ~2 minutes in the original cart)
Here is the code with just the relevant stuff (probably not very useful since no error happens, but at least it's a good summary):
I tried to find the souce of the bug by reducing the code while still having the bug. This left me with this code:
poke(0x5f2d,1) function str_to_table(str) local tab,sptab={},{} for i=1,#str do if sub(str,i,i)=="," then for j=i+1,#str do local strn=sub(str,j,j) if(strn=="|")add(sptab,tab)tab={}i+=1 break if strn=="," then local s=sub(str,i+1,j-1) if tonum(s) then s=tonum(s) elseif s=="" then s=0 elseif s=="t" then s=true elseif s=="f" then s=false elseif s=="{" then s={} end add(tab,s) break end end end end if (#sptab>0) return sptab return tab end function unpack(list,from,to) from,to=from or 1,to or #list if from<=to then return list[from],unpack(list,from+1,to) end end function to_tab_unp(tab) return unpack(str_to_table(tab)) end function _init() cls(7) level,difficulty=310,0 while abs(level-difficulty)>25 do for i=1,12 do to_tab_unp(",,,,,,,,,,") end end _init() end |
This generates the bug at about 1 second.
Let's try to change things to see how it's affected:
Shortening the string to ",," makes the bug pop in 4 seconds;
Removing the FOR loop (leaving just the while loop), no bug after several minutes;
Changing the FOR loop length (with the ",," string):
to 1 - prevents the bug
to 2 - bug happens instantly
3 - half a second
4 - same as 3
5 - 7 seconds
6 - Didn't produce the bug in <2 minutes
7 - Same as 6
8 - Bug in less than a second
9 - Same as 6 (about 9 seconds with the ",,,,,,,,,," string)
So essentially changing either the length of the string or the length changes wildly how much time it take for the bug to happen, while in normal circumstances it shouldn't (especially changing the for loop, since it's not affecting anything)
With ",,,,,,,,,," and FOR<=12:
Changing the while loop to "while 30>25 do" - no bug in 2 minutes
Changin the while loop to "for j=1,10000 do" - no bug in 2 minutes
Removing the outer loop - bug in 3 seconds - no bug in 2 minutes
With ",," and FOR<=2:
Changing the for=i variable name - no effect
Changing the while loop to "while 30>25 do" - bug in 2 seconds
Changin the while loop to "for j=1,10000 do" - bug in 3 seconds
Removing the outer loop - bug in 3 seconds
Without any loop (_init() at the end) - out of memory in 10 seconds. Still can bug if I change the string to ",,,,,"
Moving the code from _init() to _update() - no bug in 2 minutes; Instant bug by changing to for<=3
Just "to_tab_unp(",,")" inside the _update() loop - no bugs
unpack(str_to_table(",,")) instead of to_tab_unp(",,") - no bug in 2 minutes
Tried unpack(str_to_table("...")) in the original cart, still bugs
unpack({0,0}) doesn't seem to bug
Removing 'elseif s=="" then s=0' or 'elseif s=="t" then s=true' or 'elseif s=="f" then s=false' in "str_to_table" doesn't prevent the bug, and doesn't change the "timing" of the bug, but removing all 3 prevented the bug from happening at the expected time.
It seems to me that the bug happens when you combine the unpack code with the str_to_table while in any kind of loop, so a lot of unpacking and string conversion happens in the same frame...
So I tried to go to the original cart and put only the unpack code in the character creation loop:
asdd will be the unpacked table, declared outside of any loop:
asdd=str_to_table(",,,1,,f,25,2,-1,") - removing the third item "{" to prevent all characters using that same table
to_tab_unp(",,,{,1,,f,25,2,-1,") is swapped for unpack(asdd)
And then this happens (after several minutes running):
The same error (attempt to compare function with number) occurred on a completely unrelated piece of code. It would draw the item under Jack of Spades in the character selection UI, you can see it's black because the error happened exactly there. The characters are drawn left to right so that would be the last item draw. Seems really unrelated...
At this point it seems to me that the bug stems from having a huge loop that holds the game on the same frame for a while and at the same time having a function that uses a function as argument. At some point some kind of overflow happens that should be cleared at the end of the frame, but the loop holds it for too long. When the overflow happens functions that use functions as arguments have a probability of generating this error: pico-8 tries to use the function itself as a variable instead of the result of that function.
So to be sure the error is not related to my to_tab_unp function I used just "unpack({0,0,1,0,false,25,2,-1})" in the character generation. After a few minutes:
The last thing to check is generating characters without the unpack code, so I removed it, leaving just normal variables on the character generation. Left for lunch and after 2 hours, no errors.
I think it's safe to assume the bug will only happen when combining several loop layers (to the point a frame takes more than 1/30s) with functions that have a function as an argument. I don't think I can dig any deeper than that, so unless zep wants to look into it at some point the issue ends here.
For Jack of Spades I'm pretty sure I won't run into this bug as long as I don't use the unpack function inside a loop while having a brute force loop that takes more than a few frames(this is where it all started to begin with, I used the unpack/to_tab_unp codes for months, but the bug only popped when I used brute force to generate random enemy battle formations).
I removed the piece of code that generated the bug when creating a character, but today the bug happened again when drawing a character:
It was on the first level when I reset the game. So I think it was because on the first frame is where I load a lot of variables using str_to_table. Checking the CPU in the first frame rpves it: it only surpasses 100% on the first frame, but not when loading a second level (resetting with _INIT() below):
So what I did was prevent the game from drawing in the while the game is loading those initial variables. It seems it worked - the "MAX CPU" is <1 meaning it never surpassed 100% (resetting with LOAD() below):
I hope it works now, gonna do some stess test overnight 8)
[Please log in to post a comment]