Posts for r57shell


1 2 3 4 5
15 16
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
things like 7zip may help only if duplicated file is close enough in "flat" view. So, for example, if 7zip will pack stuff in order of directories, all copies will be 1 GB below, so it won't reach them to detect copy, and will dump them again and again. This is dependent to Dictionary size. If single directory is compressable enough, using 7zip is easy way to reduce size. But if they hardly compressable, then better to search for special software, or at least use revision control stuff, like git / svn, but if you're not familiar with this stuff you may ruin all :D for example, git under its hood using so called blobs for storing different files, so in theory it will store only different files in the end. Perhaps it will make new blob for each change even if you replace file to older version that already was in history. So, git and svn is not made for it. Also, I don't know how fast it would switch versions. Also, there are probably revision control systems more suited for games. Git / SVN is not supposed for binary data, their key feature is text files, but they allow binary files in source tree. So, you may try to google "git for games" or "revision control for games" or "git for resources" and etc.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Dimon12321 wrote:
Never liked splitted encodes. Who needs them?
Splitted encodes are inevitable if you have long run. Or if you have big resolution. Gens never had big resolution, but I'm planning to do atlas encodes with it so I had to investigate bugs involved.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Sadly there is no automatic way to optimize it in this way. You have to know game mechanics and tune it. The whole idea is to bake building blocks of level into premade functions. Someone should find out what are building blocks, and how they should be baked.
Post subject: Gens splitted Encode
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
There is warning:
When Gens splits videos at 2GB, a video frame is lost at each split. There is no correct way to fix this, other than to use a lossless codec which compresses well enough to avoid making the split in the first place.
at page: http://tasvideos.org/EncodingGuide/VideoDumping.html#Gens All information below is for gens-rerecording. I was encoding 10000 frames of several movies, each avi was split into approximately 50 parts. From my tests, it turns out that nothing is lost, if you have turned off FrameSkip and you have CleanAVI option turned on. Issue comes from different moments of time when sound and image is coded into avi. All data is stored. Audio of last frame may be placed in next avi, thus having bad effect for some muxers that you'll use during concatenation. For example, you're using ffmpeg concat demuxer. You have file qwe.txt with content:
file 'g:\dedede\Demolition Man (UE) [!].avi'
file 'g:\dedede\Demolition Man (UE) [!]002.avi'
file 'g:\dedede\Demolition Man (UE) [!]003.avi'
...
and then you use ffmpeg -f concat -i qwe.txt ... if you encode both video and audio, ffmpeg will try to sync all stuff and it will bend audio to match video. but if you extract all audio like this:
ffmpeg -i "Demolition Man (UE) [!].avi" 001.wav
ffmpeg -i "Demolition Man (UE) [!]002.avi" 002.wav
...
and then concatenate all audio using concat demuxer file:
file 001.wav
file 002.wav
file 003.wav
...
then encode video and audio separately and mux -> you'll get correct encode. this is ugly approach. there is better. just use same qwe.txt with all avi to encode whole video with no sound using concat demuxer, then use same qwe.txt with all avi to encode whole sound without video using concat demuxer and then mux it. last step is ultra fast. I was using ffmpeg-20180418-223f3df-win64-static other way is to use avisynth:
avisource("Demolition Man (UE) [!].avi")avisource("Demolition Man (UE) [!].avi")+avisource("Demolition Man (UE) [!]002.avi")+avisource("Demolition Man (UE) [!]003.avi")...
it will work fine. Now, appendix: in old gens rerecording like gens-rerecording 11, if you have frameskip, you'll have not-updated frames in encode. For example for frameskip = 8 you'll have 8 identical frames each 8 frames. In other words, each skipped frame will be duplicate of previous non-skipped frame. But if you turn on CleanAVI option, it may fix it. Also funny note, that encode works well even with latency-compensation and sonic tas tools while they draw collision overlay :o
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Okay, I had time this time. Lets start from clues: RAM:FFC038 - hp RAM:FFE574 - score RAM:FFE578 - lives This is found by RAM Search. Now, after you set breakpoint on write to them, when you collect item: PC:53940 - increase hp PC:6A2A - increase score PC:6A70 - increase lives you may notice that it is called from 4EFE, and it is determined by byte at $0 offset from a0 which is some address of structure of item. Now, after you set breakpoint on write to that address: PC:1DF00 - grab hp. (set the byte to $DC) PC:1DEB8 - grab gem. (set the byte to $D8) PC:1DEE8 - grab life. (set the byte to $D4) and all this determined by byte at offset $3B in player structure at PC:1DE48. So, when you set breakpoint on write to $FFC03B, you'll hit breakpoint at PC:53406 which is just copy from byte at $3E offset of item structure to $FFC03B. So, item type is determined by byte at $3E offset in item structure. Now, when you set breakpoint ot $3E of spawning item from meteor, you'll hit breakpoint at PC:52D26. It is just copy from some structure. Offset is determined by byte at $17 in item structure at PC:52CEA. Set breakpoint to it, and you'll hit breakpoint at PC:48430. Now you know that type of item from meteor determined by word at RAM:FFEA0C, by modulo 4. So, depending on remainder of division by 4 of value from RAM:FFEA0C, you'll get one of 4 items. If you watch that value a bit, you'll see that it's some kind of frame counter. So, item drop from meteor is determined by frame when it drops. Thus, it should be easy manipulate, only one trouble is that you hit meteor in various time depending on distance to it. Also, there is condition on byte at RAM:FFFE02 at PC:52CF0. And it is obviously difficulty level. The only thing it changes is what options you have. Normal / hard difficulty: 0: life / life 1: statue / statue 2: star / star 3: blue star / yellow star RAM:FFE652 meteors counter. when it is zero - you don't have an item. In super difficulty mode there is no items from meteors.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
I did very small research: PC: 4EFE - looks like evaluation of objects. PC: 5382 - looks like thing that does sprite / object allocation. PC: 1E5B6 - looks like spawn of star / gem. PC: 52D4E - looks like thing that does check for hands grabbing item. (repeatedly called when an item is on screen) So, you can search condition of item spawn using this info. also RAM:FFC038 - hp, RAM:FFC016 - state (83 for grabbing) I wasn't able to look into that RNG because I have to walkthrough up to the point.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
theripper999 wrote:
Does this answer your question?
Yes. Also I was surprised that you're killing first boss by kunai. Hit from run does not require opening, and looks like dealing same damage.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Easy yes vote for one of my favorite games. I would like to see speed of simple jump in "movement" section. Otherwise it isn't clear to me, should you maximize jump kick time or not.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Easy yes vote from me. Rare case when I vote yes without even watching :D
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
my main goal was to be able play the game
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
IDK what you doing, but I'm planning to add encoding method into my sonic atlas... Just because of this event. Here is links: http://tasvideos.org/forum/viewtopic.php?p=470260#470260
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
XTREMAL93 wrote:
в бизхок при создании AVI есть функция resize. качество будет таким же как с виртулдаб?
Я лично делаю так делаю временные энкоды, и всем рекомендую: [Custom] формат выбираю. В поле для настроек пишу:
-c:a libvo_aacenc -vf "scale=1280:896" -sws_flags neighbor -vcodec libx264rgb -crf 0 -f mp4
Это для 1.13 версии, не знаю что там в новой. Главное в scale указать правильные размеры в пикселях итогового изображения. Тут соответственно 1280x896 это в 4 раза увеличенное сеговское 320x224. Можно просто написать scale=iw*4:ih*4 - это означает просто в 4 раза больше.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Alright. For sake of completeness, I've made some comparison. https://gist.github.com/realmonster/e7ceadff746750e795822e0a95f42eb1 It has 5 files: demolition_man_1_raw.lua - naive implementation of drawing collision overlay. demolition_man_2_ranges.lua - naive implementation but having tricky ranges calculation. demolition_man_3_loadlevel.lua - get rid of all memory_readsomething by loading whole level on Lua side. demolition_man_4_empty.lua - also mark empty tiles and tiles full of same color demolition_man_5_baked.lua - proposed solution Test: PC: my shitty laptop. Bizhawk 1.13.2 First level, first floors. FPS: 1-2, 1-2, 6-7, 6-8, 60 - Bang.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
According to info that feos provided, you do macro #2 (index from 1), and when it comes to command #3 (index from 1) it tries to find character with some kind of id = 6 in Obj_Fighters. It is table starting at address 0xFFFFF500. It's scanning it by steps of 0x40 and looking at offset 0x12 for value 7, "because character ID in battle is actual ID + 1". Code offset is 0x5630. Next, it can't find character with id 7 so it keeps stepping by 0x40, eventually overflowing address register and it turns into zero. So it warps around, and continue search in ROM, because addresses starting from 0 is ROM. Eventually it finds some offset with value of 7 at offset 0x12, and reads its 0x0 offset because it should be "battle obj ID". It happens to be 0x27. Next, macro action also pick "other character". Now, the game wants to find out their order in Battle_Turn_Order. So it tries to find 0x27 in Battle_Turn_Order, but there is no such character, and it continues searching, until it eventually find 0x27 somewhere outside of the list, at index 0x158. Max index is around 20 though. I'll call this 0x27 as "bugged". Next, because "other picked character" is earlier in the list than "bugged" one (index 1 vs index 0x158), it wants to move it right after bugged like this: imagine current order is: 1234567 and "other" is 3, and "bugged" is 6, then it wants to make following: 1245637 So it moves everything between them one position to the left, and moving "other picked" right after "bugged". But each entry of this order is 4 bytes, and our "bugged character" is found at index 0x158, so it's shifting all that memory by 4 bytes to lower address. And this range contains some of values that are stored into SRAM when you ask to save. Also there are some game flags, world index, and etc. If "other picked" would later than "bugged" it would not shift anything. In short: bugged macro while searching bugged char finds bugged id, and then when bugged id is scanned in Battle_Turn_Order it finds bugged index, and then shifts everything in between by 4 bytes, and moves first 4 bytes to end of this shifted bytes.
Post subject: Re: i want to cry, why does nobody help with this :(
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
TASeditor wrote:
The line drawing algorithm is used to set the analog stick position. Think of drawing a line on a 256x256 grid from origin to the edge with the optimal input angle an then finding the integer position on the grid which is closest to the line.
Sort all candidates by angle, and then just binary search in it.
TASeditor wrote:
I'm not seeing any unused code.
Sorry, my bad. I thought best is not used, but now I see it used for restricting candidates.
TASeditor wrote:
r57shell wrote:
Lifehack: 1) Remember point where cursor is aiming at. 2) Just zoom somehow 3) Parallel translate everything in a way that remembered position will match current aiming poisiton.
Well, I know that it zooms into where the (xFollow;yFollow) point is.
Probably you don't get what I say. What I say is actually formula in very simplified way. Third step is just: calc difference between where you was pointing, and where you're pointing now, and then multiply/divide by scale.
TASeditor wrote:
The character also zig-zags along a straight line, I don't see how zig-zagging along a circle would be a problem, this is expected. Of course the amount of zig-zagging needs to be minimized.
Depending on how character moving, you can or can not optimize zigzaging straight ahead. For example, if he is constantly adding some vector with fixed precision value, you should better apply one stick position during whole segment. In a bit worse mechanics - you need to pick exactly two stick positions and then: first poistion for n frames, and second position of stick for all other frames. But if camera position affecting stick effect, then it's not simple anymore. In that case I don't think walking along is best way, but at least it's good first approximation.
TASeditor wrote:
r57shell wrote:
Perhaps required skill level is too high. I can help with some geometry, with some optimization problems, but not beyond that.
My programming skills aren't very high either.
Having any programming skills is already high level.
Post subject: Re: i want to cry, why does nobody help with this :(
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Disclaimer: I didn't try your script, and I don't planning to.
TASeditor wrote:
Functionality for calculating the stick coordinates: It uses a line drawing algorithm, which is more accurate than calculating the values with trigonometry with integers. Incrementing and decrementing the stick angle also uses this algorithm. There probably isn't a better way to do it.
Line drawing algorithm is actually also calculating values with integers. I don't know why do you use it here, probably because you didn't define the problem. Also, your line drawing implementation is running unused code.
TASeditor wrote:
Point when player starts moving to next waypoint: It makes the vector line equation L: X = A + l*(B-A) , where A is the start point, B the goal, X the current player position. Solve the equation for l and check if l >= 1 then set next waypoint in list as the goal.
IDK what approach do you use, but there is simple one, it is called dot product. Just calc l = (X-A, B-A)/(|B-A|*|B-A|) where (v1,v2) is dot product. You can verify it for example in desmos.com/calculator (just piece of awesomeness). But it would allow point to be not on the line, so you also need to check is it on the line. To do that, calculate d = [X-A, B-A]/|B-A|, where [v1,v2] - is cross product, and d = distance to the line.
TASeditor wrote:
• Fix zooming: Zoom into point where mouse courser is pointed at.
Lifehack: 1) Remember point where cursor is aiming at. 2) Just zoom somehow 3) Parallel translate everything in a way that remembered position will match current aiming poisiton.
TASeditor wrote:
• Add Circle segments and bezier curves as trajectory to follow.
To me, it looks kinda strange. You're telling how to move to character, instead of making him move optimally from point to point. For example, imagine you tell character to move along circle with slightly smaller/bigger radius than character would move naturally. So, it would zig-zag along this circle because he is either too close to center, or too far from circle itself. On the other hand, in racing games you tend to select any path that has most speed and fitting inside borders. Same can be used in games like Doom etc. I know they don't use analog stick though. Regarding to just code: you use atan2 a lot. I guess you can get rid of that. Most of trigonometry stuff can be done without it. Also I would recomend to make local shortcuts to abs, atan2, floor, etc. You may compare performance with it. But don't optimize things too early. No reason to take effort to optimize code that will soon be deleted. Main problem: idk how much this code is reusable for different movement game mechanics. What is really good is: drawing stuff is reusable for sure :)
TASeditor wrote:
i want to cry, why does nobody help with this :(
Perhaps required skill level is too high. I can help with some geometry, with some optimization problems, but not beyond that.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
creaothceann wrote:
Unfortunately I only do (Free) Pascal, which has Pascal Script.
Probably. I just want to say that some popular scripting languages like JavaScript, Python, Perl for example are kinda same in this aspect. Don't know about Pascal Script though.
DeHackEd wrote:
I feel like we're overdoing it here. I mean, if it comes down to it you could just write a C function and require() it into Lua and have it do all the heavy lifting.
It would not help with environment API calls: like gui.drawPixel in bizhawk. It would not reduce their count. Also, when you make Lua dll you should compile it with same Lua version. This is additional headache.
DeHackEd wrote:
As an aside, _G["string goes here"] is faster than you think. Lua has an internal table of strings and so the hashtable lookup is really just looking up an integer field. There's no actual hashing of the function name on each iteration.
You're right. I didn't know that. Hashing is done as soon as string is made. It doesn't change fact that it does hashtable lookup in _G. On the other hand, local variables are on the stack. Also, I've separated version of this algorithm. Here: https://gist.github.com/realmonster/93090d4ef0b40c1b88d62f8840fad675/afc1653f74b91d7b95b9a90d80b9ddc5796237eb#file-demolition-man-lua-L82 Now it also scans tile in all eight orders, and picks best result it was able to find. You can't apply it mindlessly. You need to know full set of tiles that you want to bake. To bake tile, you just need to make new instance of tile_splitter, then fill it with add, and then call split, and it will return list of rectangles of same color. Last step is completely your responsibility: you need to convert list of rectangles into string that contains Lua code suitable for your case. Code example is there, just look for tile_splitter call in level loading, and tile_generator that does conversion of list into Lua code.
Post subject: Re: Improving Lua performance using baked functions
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
creaothceann wrote:
Sounds like it's time to switch to an actually usable language...
Any suggestions?
Post subject: Improving Lua performance using baked functions
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Lua internals Alright, lets start from some info about Lua internals. As for many other script languages, each mention of some variable in some Lua expression is actually taking time to get its value. For example, if I write following code:
Language: lua

for i = 0, 10 do print(i) end
It takes some time to get value of i and pass it into print. More important that here print is also variable. It's so called global variable. Here it's storing API function provided by environment. So, getting print function is also taking time. Again, more important, that taking here value of print is much slower than taking value of i. Because i here is local variable. Local variables is working faster than global variables, mostly because local variables doesn't have name in runtime, instead of that, they have indexes. And all actions "take local variable value" is just getting value by index, which is fast. On the other hand, global variables are stored in _G table. It's global table for all global variables. And getting some global variable is essentially taking value from table by its name. So following code is same:
Language: lua

_G["print"]("qwe") print("qwe")
And because indexing by string is more harder task, including hash calculations if it's using hashtables as implementation, or other stuff - it works much slower than just getting value by index. This means that this stupid-looking code is actually works faster:
Language: lua

local print = print -- store global value into local for i = 0, 10 do print(i) end -- use local variable
Now, a bit about print itself. As I said, it's API function provided by environment. Each time you call environment function, Lua doing following: Lua->API->Environment 1) Lua calls API function provided by environment 2) API function pulling some info about: arguments count, their types 3) API function does some sanity checks about call correctness 4) API function does actual work with environment internals Lua<-API<-Environment 5) API function is taking results from environment 6) API function is pushing results to Lua 7) Lua continues execution of Lua code So, basically each environment API call consists of two translations: from Lua to Environment and backwards. Even though you can't avoid calling API, you may try to reduce count of calls, to reduce unneccessary calls to improve speed. Case We want to draw collision data in 2D platformer. In this post I'll talk mostly about this case. What do I mean by "collision data"? Simple: if some object is changing behavior when it's touched <- it's "collision data". As for now, I'll talk only about tile based 16x16 pixel collision data. Alright. We have 16x16 collision blocks, they have pixels, each value of pixel may have different meaning, like: ground, ceil, wall, ladder, and so on. It's very handy to draw overlay over game screen where each collision pixel is colored by its color. But how code would look like? It would be something like this:
Language: lua

for x = ?, ? do -- here ? is some expression calculating bounds for x for y = ?, ? do -- here ? is some expression calculating bounds for y local tile = get_collision_tile(x, y) -- to avoid finding corresponding tile 16*16=256 times for i = 0, 15 do -- 16 by y for j = 0, 15 do -- 16 by x local v = get_collision_data(tile, i, j) -- get collision pixel if colors[v] ~= nil then -- if it has color, then you want to draw here gui.drawPixel(x+i-scrollx, y+j-scrolly, colors[v]) -- scrollx, scrolly is camera position end end end end end
If colors[v] is nil this means that v value doesn't affect behavior at all, in other words: nothing to draw. For example you should have v for air, and you'll set colors[air] = nil, to avoid draw every space where you can walk freely. (Demolition Man for Sega Genesis) This code above is actually already optimized. It'll only translate values to colors and position relative to tile into global position. Nothing to optimize, right? No! First optimization that is often done is: process only tiles that is on screen. It's done by more carefully cooking ranges of first two for loops. Example is something like that:
Language: lua

local left,right,top,bottom = scrollx,scrollx+320,scrolly,scrolly+224 for y = max(0,floor(top/256)), min(hblocks-1,floor((bottom-1)/256)) do for x = max(0,floor(left/512)), min(wblocks-1,floor((right-1)/512)) do
I don't want to explain it in details, but idea is simple. x and y should take values of block if and only if some part of it is visible on the screen. For 320x224 screen as in my case it will process at most 21x15=315 blocks. Also, for each tile we can calculate sx, sy = x-scrollx, y-scrolly and use them in gui.drawPixel call reducing few operations: get value of scrollx, scrolly, and two subtractions. Now, what is next? Next is what is all lua internals part was about. What API environment function do we see here in code above? It's gui.drawPixel. It should be something about it. Nope. (actually yes but... later) We are calling get_collision_tile and get_collision_data. But wait, it's not API environment functions. It's our custom made functions for reading game data. Yep. But what it has inside? It has multiple calls memory.read_something calls, each of them is environment API call. First, you should make local variable for them, to avoid looking for them in global table _G every time you want to read something from memory. Time to remind our goal: we want to reduce count of API calls. Here API calls are memory.read_something. How can we get rid of them? Answer is simple: read level only once, and store its whole structure on Lua side! But how can we do that? Just each time when you want to draw collision overlay, check for current level. If it changed, forget all data about previous level, and load whole level into Lua again. It'll require time only when you change level. After that, code of get_collision_tile and get_collision_data should not have any API calls. After you did that, you may think: wait, why do we always convert collision pixel value(v) into its color? (colors[v]) Yes, now we can "bake in" collision color instead of collision value straight into collision tile data! What's next? You may notice that many of collision tiles are just empty. Full of air. (wait, you said empty!) So, you don't want to spend time on those tiles. You may make some table of empty tiles and before processing 16x16 pixels check is it in list of empty. If it is, then skip processing. Note: when I say "check in list" - I don't actually mean that you should have it as some kind of list. Best way to implement that is just one big table, and if value at index of tile is true then it is empty. So, code is just
Language: lua

if empty_tiles[tile_id] then continue end
You may came up with some similar ideas, like store table of full_somevalue tiles, and so on... Well, it's way long introduction to actual new approach. Baking time! What if we would be able to make list of calls for each collision tile? For example, if it has 16 non-empty pixels, why not to store function with its arguments into list, and then just execute it? Fortunately, we able to do that! Like this:
Language: lua

calls_list = { {gui.drawPixel, 5, 7, 0xFFFF00FF}, {gui.drawPixel, 10, 10, 0xFF00FFFF} } for i = 1, #calls_list do local b = calls_list[i] -- single list entry b[1](x + b[2], y + b[3], b[4]) -- where x, y is shift to align with camera position. end
Using this technique, you may bake all collision tiles into lists of calls, during level loading on Lua side. Now we have solution for making and running call lists. How about optimizing call lists? What else do we have besides gui.drawPixel? We have gui.drawLine! Can we utilize it? Of course we can! You may think of gui.drawLine as batch of gui.drawPixel with same color. So, if we able to split collision pixels into bunch of lines, then we can draw them instead. It will reduce count of API calls and thus, it'll improve performance of script. How can we do that? For example like this. If color of previous line is same as next pixel, and there is no gap in between - just increase length of line. Here is a picture: https://i.imgur.com/k7Xcw9e.gifv Also, good implementations of drawLine method is doing sanity checks only in the beginning, and drawing all pixels straight ahead. This is done using so called "clipping". Original line reduced to segment of it that is on screen, and only pixels of that segment is efficiently enumerated, without checks for leaving bounds. On the other hand, each call of drawPixel does check weather position is on screen or out of bounds. But drawLine does it once for the whole line. Next, you may think of gui.drawBox as batch run of gui.drawLine. Can we utilize it? Of course we can! Similarly to lines, we will look for previous line, and if it has appropriate starting and ending position, then we will convert it into box. Here is a picture: https://i.imgur.com/PxeTKei.gifv Similarly, good implementation of drawBox does coordinates check only once. It's done by "clipping" - transforming coords passed to the method into new coords - part of box that is on screen. And no additional checks required during fill. Now we have a small trouble. gui.drawPixel, gui.drawLine, gui.drawBox have different arguments. To handle variable count of arguments for functions, you would need some workarounds. You may want to use unpack function, but you need to add camera shift to coordinates, so it's not an elegant way. You may check vs function that you want to call, and then call it as intended. You may make supplementary functions that use always four coordinates and then calling API function, but this will lead to unnecessary addition for coords that is not used. gui.drawPixel for example. Also, gui.drawBox has two colors: fill and outline. Checks like that, intermediate functions, and other stuff may reduce gain. Perhaps we can "bake" even more? We need to bake more! Even though Lua is interpreter, each time you include some file using require, it's actually compiling code that is loaded in some kind of intermediate language code. This step is required to have decent performance. Otherwise you'll end up spending most of the time parsing each line over and over again. This means, in theory we can generate .lua files and then load them using require, with all tiles recompiled into functions, and then simply call that functions. But in practice, there is better function. There is loadstring. It is loading code pretty much like require does, but is loading code straight from the string! Also, it doesn't check "was it loaded already?" which is annoying part if you would use require because you would have to always generate new name for generated file. That's it! Just generate Lua code for each collision tile, and then simply call it like this:
Language: lua

cdata[idx1](sx,sy) -- shift x, shift y to align with camera
And, to make functions work fast, you should make local variables for functions, like this:
Language: lua

local gui_box, gui_line, gui_pixel = gui.drawBox, gui.drawLine, gui.drawPixel
So, for the following picture: https://i.imgur.com/4kmJbBK.gifv Code is following:
Language: lua

local gui_box, gui_line, gui_pixel = gui.drawBox, gui.drawLine, gui.drawPixel return function (x,y) gui_pixel(x+0,y+0,16777113) gui_box(x+1,y+0,x+2,y+1,16777113,16777113) gui_pixel(x+2,y+2,16777113) gui_box(x+3,y+0,x+4,y+3,16777113,16777113) gui_pixel(x+4,y+4,16777113) gui_box(x+5,y+0,x+6,y+5,16777113,16777113) gui_pixel(x+6,y+6,16777113) gui_box(x+7,y+0,x+8,y+7,16777113,16777113) gui_pixel(x+8,y+8,16777113) gui_box(x+9,y+0,x+10,y+9,16777113,16777113) gui_pixel(x+10,y+10,16777113) gui_box(x+11,y+0,x+12,y+11,16777113,16777113) gui_pixel(x+12,y+12,16777113) gui_box(x+13,y+0,x+14,y+13,16777113,16777113) gui_pixel(x+14,y+14,16777113) gui_line(x+15,y+0,x+15,y+15,16777113) end
So, whole problem is reduced to following task: how to split picture into minimum count of axis aligned rectangular areas of same color? Depending on your solution of this task, you may gain more speed. In the end, if you have way to draw pictures, you may "bake" each collision tile into a picture, and then draw it instead. But solution discussed above works even if you can't draw picture, or if it is slow. Ahhh. Here is part of code that is actually implementation of algorithm above: https://gist.github.com/realmonster/93090d4ef0b40c1b88d62f8840fad675/5310f3bf8463ae6e0a766e4608f268fd28762184#file-demolition-man-lua-L107 And, according to pictures above, atm it has some bug with building blocks not as intended. Anyway, it works.
Post subject: Demolition Man
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Alright, I'm starting this topic. We have cancelled submission: #4840: arandomgameTASer's Genesis Demolition Man in 09:26.28 I did maps: http://vgmaps.com/Atlas/Genesis/index.htm#DemolitionMan And today I've published script: https://gist.github.com/realmonster/93090d4ef0b40c1b88d62f8840fad675 I haven't implemented in script few things that I've found, but I think I'll add it soon or later.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
just astonishing TAS. I guess BlueGlass would agree :D
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Spikestuff wrote:
Spike what's with the specific time frame? 1.6.0a the Genesis Core was introduced to Hawk in 2014.
I remember back then, not sure exact time but it wasn't stable and was crashing every now and then, and also it had desync issues. Even though I have now bizhawk 1.13.0 released in Jun 2017 - it still has some issues. And I can't run any newer version. This version is the latest that I can run. Because I'm still using laptop from 2012 :) So, you may run and yell that "MY COMPUTER IS SHIT". If you require from TASers to have decent computers then I'm out.
Spikestuff wrote:
The only person who gave a valid point whilst you and Archanfel were shitposting was WST.
Please, can you describe what is valid point, and what is invalid point regarding emu selection? If there is some section in submission rules it would be best.
Spikestuff wrote:
Linux support is a great reason too. The push is needed for you folks to actually needs to port it to something that already has a foundation in the Linux area for the better emulator, aka lsnes. Since WINE isn't doing the job for you.
Are you saying that we need to force someone to write code? Sounds like a plan. Keep in mind, for those who making TAS for themselves, their emulatior choice is not depending on TASVideos rules. Even more, nothing depends. Only their own feeling what emu and what TAS they like to do. And only by coincidence resulting TAS is acceptable here. Just because people tend to use better tools and interesting runs. Or they are with other goal from the beginning: make TAS acceptable for TASVideos.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
GJTASer2018 wrote:
Then you, sir, have missed THE ENTIRE POINT of why this website exists. Console verification has always been the ultimate objective for tool-assisted speedruns and this website:
tasvideos.org/ConsoleVerifiedMovies.html wrote:
Since they started, tool assisted speedruns were designed to make it theoretically possible, given super-human abilities, to recreate them on an actual console.
First: your quote says more like this is side effect. It wasn't main goal. Main goal was to show superplay. Second: I would accept arguing for console verification if we would be closer to console verification of genesis runs. But for now, both gens runs / bizhawk (genplus-gx) runs should be altered to make them sync on real console. This means that both of them not accurate. And for console verification it's not so important which one is "more accurate". You need "just" accurate one - which we don't have yet.
Experienced Forum User, Published Author, Player (97)
Joined: 12/12/2013
Posts: 376
Location: Russia
Thanks to you, DERP! :) Awaiting submission. :)
1 2 3 4 5
15 16