This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
KingofGamesYami's profile picture

Creating a Redirect Object

Started by KingofGamesYami, 23 March 2016 - 03:36 PM
KingofGamesYami #1
Posted 23 March 2016 - 04:36 PM
Code.

Currently, I'm trying to debug my blit function, which is weirdly erroring on line 51 with 'attempt to index ? (a nil value)'. I've proven that internalText exists, and that internalY is always 1. Strangely enough, it errors on the 5th call, not the first.
moTechPlz #2
Posted 23 March 2016 - 05:38 PM
Not sure if this is the culprit but the code increases the string length by one.

local internalX, internalY, internalText = 5, 1, {}

internalText[ internalY ] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
text = "blabla"

print( internalText[ internalY ] )

internalText[ internalY ] = internalText[ internalY ]:sub( 1, internalX ) .. text .. internalText[ internalY ]:sub( internalX + #text )

print( internalText[ internalY ] )
Edited on 23 March 2016 - 04:40 PM
KingofGamesYami #3
Posted 23 March 2016 - 05:59 PM
I thought that was an issue, the problem is I gotta figure out where to change the :sub. Also, that wouldn't cause an attempt to index error, since it doesn't set anything to nil. There's doubtlessly many more issues I need to fix, I just need it to run before I can fix those.
Edited on 23 March 2016 - 04:59 PM
Dragon53535 #4
Posted 23 March 2016 - 06:56 PM
When you say it happens on the 5th call, are you calling anything else in between that?
Dog #5
Posted 23 March 2016 - 07:33 PM
While this isn't the problem you're looking for, I was wondering if line 133 is intentional - it currently sets getTextColour equal to getBackgroundColor
KingofGamesYami #6
Posted 23 March 2016 - 07:33 PM
Well, the way I'm testing is by redirecting to it and then shell.run(ing) the paint program. So, maybe? I looked at every instance of the variables involved, and I can't find a single instance where they would be nil - and it never outputs nil either. The only reason I know it's the fifth call is it prints my debug things to the native terminal 5 times before that.

While this isn't the problem you're looking for, I was wondering if line 133 is intentional - it currently sets getTextColour equal to getBackgroundColor

Thanks for pointing that out, fixed. Not intentional, as I said before I need to do a lot of testing - once this runs without outright erroring.
Edited on 23 March 2016 - 06:34 PM
Dog #7
Posted 23 March 2016 - 07:47 PM
Again, not the problem, more of a question if you will…

I noticed in your update function (specifically lines 30 and 34) that you have two loops (one nested inside the other), both using y as a variable. How does the code within the nested loop know which y value to use?
Dragon53535 #8
Posted 23 March 2016 - 07:49 PM
It uses the most local y, so it's own. The one above it isn't used. Since the first y is the index of the monitor, I don't think he cares.

Edit: Wait, wait, why is tMonitors a nested table? Shouldn't it just be a table full of wrapped monitors?
Edited on 23 March 2016 - 06:52 PM
Dog #9
Posted 23 March 2016 - 07:55 PM
Thanks, Dragon :)/>

I *think* tMonitors tracks the stitched monitors, so each tMonitor entry has a table of multiple monitors within it.
Edited on 23 March 2016 - 06:58 PM
KingofGamesYami #10
Posted 23 March 2016 - 08:05 PM
tMonitors is indeed nested tables, I have 6 monitors attached to it. I have it set up so that it's visually similar to the physical placement:


local tMonitors = {
  { <1,1>, <2,1>, <3, 1> },
  { <2,1>, <2,2>, <3, 2> },
}

Yeah I don't care about the y value in the upper loop, it's not used. I could change it, but I'm using it to remember how the layout of my table structure is.

Edit: actually, I'm messing with the update() code in game right now, it's rendering everything 1 character to the right at the moment (or maybe that's the buffer?)

Edit #2: I think the above is related to that

Edit #3: Fixied!

Note: I am editing the paste I posted in the OP frequently.
Edited on 23 March 2016 - 07:12 PM
Dragon53535 #11
Posted 23 March 2016 - 08:09 PM
Would you mind adding this line like right above 51?


term.native().write(internalText[internalY])
That way we can check if it's erroring on internalText being nil, or that specific spot.
Edited on 23 March 2016 - 07:09 PM
KingofGamesYami #12
Posted 23 March 2016 - 08:17 PM
Did that, and…



Dafuq?
KingofGamesYami #13
Posted 23 March 2016 - 08:40 PM
Progress:

Creator #14
Posted 23 March 2016 - 09:01 PM
That looks epic!
KingofGamesYami #15
Posted 23 March 2016 - 09:50 PM
Hmm.. Now mon.blit is erroring with 'arguments must be the same length' (this is on line 42 in the paste). I'm not sure how the arguments would ever be different lengths, since I'm using the same string.sub on all of them.
Dragon53535 #16
Posted 23 March 2016 - 11:21 PM
It looks like you're having a too long without yielding error.

Edit: Guess I got ninja'd by you confirming lol
Edited on 23 March 2016 - 10:22 PM
KingofGamesYami #17
Posted 23 March 2016 - 11:21 PM
Fixed all the bugs, now optimization is needed. I'm getting too long without yielding 3/4ths of the way through a monitor with the text scale set to 0.5, so I'm going to try and cache as much as possible.

Update: Now getting to second row before too long without yielding error. Progress!
Edited on 23 March 2016 - 10:36 PM
Bomb Bloke #18
Posted 23 March 2016 - 11:41 PM
stitch.write() will need to tostring "text".

Shouldn't clearLine() / scroll() call update()?

stitch.blit() needs to ensure the text is in bounds. It'll need to crop it if one of the ends will poke off the left / right of the display, or entirely ignore it if it won't be visible at all.
KingofGamesYami #19
Posted 23 March 2016 - 11:48 PM
Added tostring

Yes they do, fixed.

That's going to hurt performance. *smashes head against wall*. What would be the most efficient way to do this? I'm not entirely certain I need to do that at all, won't mon.blit cut it for me?
Bomb Bloke #20
Posted 24 March 2016 - 12:09 AM
write() still isn't using tostring() correctly. When calculating the length of the textColour string for eg, you can't very well base that on a nil value. Try passing it some numbers or other data types to see what I mean.

What would be the most efficient way to do this? I'm not entirely certain I need to do that at all, won't mon.blit cut it for me?

Hah, no, mon.blit() isn't going to help you. When you only want to add part of the incoming text to your buffer, you're going to have to specify that. ;)/>

The window API has an example of how you might go about doing it, and is about as efficient as you'll get.

https://github.com/alekso56/ComputercraftLua/blob/master/rom/apis/window#L103

In terms of optimising the rest of your code, cache table lookups - if you're going to index into the same position multiple times, do it once, assign the value to a new local, and then refer to that from then on.

Also cache table lengths and rep'd strings, and avoid select().
Edited on 23 March 2016 - 11:12 PM
KingofGamesYami #21
Posted 24 March 2016 - 01:31 PM
I see what you mean, fixed that.

I think I did this properly, but I might be wrong. It won't screw with a properly written program, in any case.

I got the optimization under control, I forced it to act as a buffer. I could do more optimizing, but it works now, so… Yeah.
KingofGamesYami #22
Posted 24 March 2016 - 02:28 PM
Well, now all I have to do is translate monitor_touch events, and I'll be able to actually run paint on a giant monitor.
KingofGamesYami #23
Posted 24 March 2016 - 05:32 PM
I'm having too much trouble with monitor_touch events, for whatever reason it's always getting (1, 1). Doesn't seem to matter which monitor I touch, or where on the monitor I touched.

That was dumb… Variable names.

Now touches are working on the first row, second row isn't working yet.

Update: Touches are off by 1 pixel on the second and third monitors. Touching still doesn't work on the bottom row.
Edited on 24 March 2016 - 07:39 PM
KingofGamesYami #24
Posted 24 March 2016 - 11:25 PM
Alright, I still have no idea why the second row isn't working, but I think the top row shift is a rendering problem.



It draws the last column of the left monitor on the first column of the right monitor - that's not supposed to happen, although I can't imagine what's causing it.

Also, it draws the last column of the center monitor on the right monitor. But I'm fairly certain that's caused by the above issue.
Edited on 24 March 2016 - 10:26 PM
Bomb Bloke #25
Posted 25 March 2016 - 12:42 AM
In update(), currentX / currentY are incorrectly starting at 0.

Your blit function's still looking a bit busted. Putting aside that it's not sub'ing the incoming text correctly, you're not even checking whether a visible row's in use - that one's a crash bug.

And don't try to suggest that code which doesn't do that for you "isn't proper"! It's the terminal object's job to handle that! ;)/>
KingofGamesYami #26
Posted 25 March 2016 - 01:02 AM
I think I see your point with currentX / currentY, I was thinking it'd be correct because I'm later adding them. Why can't stuff be 0-indexed like normal languages :(/>

Blit is going to be fixed, I swear! Right after I fix the valid usage scenarios. I had a sub in there that wasn't working properly, but it's hard to tell if I'm breaking things if said things are already broken elsewhere.
KingofGamesYami #27
Posted 26 March 2016 - 01:42 AM
Solved the issue with drawing, and fixed the events on the bottom monitor. Turns out I was localizing x to the function, not the loop, which meant it was offsetting the x-coordinate by the length of the top monitors. Derp.

Blit works if you give it things that are correct, but isn't working if you try to write anything to an x-coordinate less than 1 (ei 0, -1, etc.). Nothing happens. As far as I can tell, my sub calls are correct, but they must be causing some sort of problem.
Bomb Bloke #28
Posted 26 March 2016 - 04:36 AM
Blit works if you give it things that are correct,

As I was saying before, you can't go passing the blame on that one! :P/>/> Writes to out-of-bounds locations are perfectly valid.

local beforeMaxLen, afterMinLen = internalX - 1, internalX + #text
internalText[ internalY ] = string_sub( internalText[ internalY ], 1, beforeMaxLen ) .. text:sub( 2 - internalX, stitch.getSize() - internalX + 1 ) .. string_sub( internalText[ internalY ], afterMinLen )

It's important to remember that passing a negative argument to string.sub() means "start counting backwards from the right". That goes for both arguments.

Let's say internalX is 5, text length is 20, and screen width is 30:

text:sub( 2 - internalX, stitch.getSize() - internalX + 1 )
text:sub( 2 - 5, 30 - 5 + 1 )
text:sub( -3, 26 )

--# So given #text == 20, you effectively get back:
text:sub( 18, 20 )

Due to the length of the text, your starting point is way higher than it should be, and a three-character string is returned when you should be getting all of it. This problem is less likely to manifest with shorter strings, and as you move away from the left edge of the display it also becomes less likely to occur, but letting those values go negative isn't a reliable option.

You can probably envision the conditionals you'll need to implement to deal with all this, but you may be thinking "let's use more ternarys inside the sub calls" - that's actually not a good idea here; rather, you should be using your conditionals to avoid making those sub calls in the first place. Your current blit function makes them nine times a pop, even though "worst case" scenarios only need six, and "best case" requires none. Ignoring this adds up to quite a performance hit, as blit is a function which gets called a lot. The reason why Dan's window API uses all those if/elseif/etc checks within its blit function has nothing to do with readability and everything to do with execution speed.

Have a think about all the different configurations that can be presented - text going off the left and / or right of the display, lining up with the edges, or not - and you'll see that you can shift quite a bit of work away from the interpreter with a few more checks.

Edit:

By the way, I assume you've taken on my hatred of term.scroll() by now. Without it, we wouldn't need to buffer stuff within our terminal objects in the first place.

But since you have a buffer, why not go ahead and implement setVisible() and redraw()? These functions are dead handy to have for the purposes of easily reducing flicker within render-heavy scripts!
Edited on 26 March 2016 - 03:42 AM
KingofGamesYami #29
Posted 26 March 2016 - 01:32 PM
It works now, thanks! Lots of copy/paste though :(/>. I hate doing that. And yes, I did use if statements not ternaries. Even though I love ternaries.

setVisible and redraw were actually really easy to implement, thanks. (I added a total of maybe 15 lines)

Hopefully this is complete, feel free to request features / report bugs in my official post.
Bomb Bloke #30
Posted 26 March 2016 - 02:24 PM
Still a little screwy, but definitely getting better! :)/>

Line 163 (in the scroll function) is using maxy to rep characters for internalBackgroundColor (when it should be using maxx). That's a crash bug.

setVisible() should call redraw() if changing from false to true (but not under any other circumstance, eg true to true).

redraw() should do nothing if the term object isn't currently set to visible.

There're also some other problems where line lengths aren't as they should be, but it's a bit past my bedtime so I haven't proofed the blit function properly. The problems may not even be in that particular function.
Edited on 26 March 2016 - 01:25 PM
KingofGamesYami #31
Posted 26 March 2016 - 10:11 PM
Hey, fixing that error on line 163 made it so stitch doesn't crash when I terminate a program anymore. Sweet!

Implemented said behavior in setVisible and redraw()

Line length problems are probably in blit, given the amount of subbing I do in there. Thanks for the (rather extensive) help!