Live data from Hacker News

A Comprehensive Super Mario Bros. Disassembly

gist.github.com

41–50 of 87 posts

Re: A Comprehensive Super Mario Bros. Disassembly

#42

You might also be interested in the dissambly of the first pokemon games: https://github.com/pret/pokered And some other pokemon games: https://github.com/pret/pokered#see-also

I loved this article regarding the algorithm used for capturing pokemon: http://www.dragonflycave.com/mechanics/gen-i-capturing

Re: A Comprehensive Super Mario Bros. Disassembly

#43

Earlier quoted context omitted.

Lookup tables were indeed a common technique used by games in the past.

And present, too, right? It's not the same reason as it would have been in the 80s, but today in performance critical code it is not uncommon to reduce the number of conditionals for better CPU pipelining, and lookup tables are a very common tool for this.

I think the biggest difference is that modern games tend to be written for variable frame rates, stuffing floating point time deltas through equations.

A lookup table meshes much better with fixed frame rate gameplay, either with one entry per frame, or quantizing countdown timers of how many frames to wait to go to the next state.

Re: A Comprehensive Super Mario Bros. Disassembly

#44
post #36

Earlier quoted context omitted.

You can also fine-tune the feel of a jump when you're directly editing a handful of values vs trying to find a function that describes your desired results.

How so? "Trying to find a function" is editing a handful of parameters to a polynomial+exponential model -- the same thing

When you edit one coefficient of a polynomial, you change its behavior everywhere. When you change one value in a lookup table, you're only changing the value for one point in time.

Re: A Comprehensive Super Mario Bros. Disassembly

#45
post #23
post #19

Check out the section under "DemoActionData": this is where it stores (and plays) the demo you see when you don't push Start and Mario runs around on his own volition. It just simulates player input and runs it through the regular game engine. (The alternative, playing a recorded video, would have been laughably data intensive.)

Same thing goes for Super Mario 64. The popular TASer pannenkoek actually explored whether it was possible to manipulate Demo-Mario's starting position in such a way that he collects a star with the demo input (this was for the purposes of special "A-Button Challenge" speedruns, where pressing the A-Button must be kept to a minimum, but since the demo input isn't actual player input it isn't counted) Sadly I think th…

That's an amazing youtube channel. Here [1] the creator describes in an over seven-minute long video the intricacies of Mario falling asleep.

[1] https://www.youtube.com/watch?v=7OtW-LLZ2OA

Re: A Comprehensive Super Mario Bros. Disassembly

#46

Earlier quoted context omitted.

And present, too, right? It's not the same reason as it would have been in the 80s, but today in performance critical code it is not uncommon to reduce the number of conditionals for better CPU pipelining, and lookup tables are a very common tool for this.

I think the biggest difference is that modern games tend to be written for variable frame rates, stuffing floating point time deltas through equations. A lookup table meshes much better with fixed frame rate gameplay, either with one entry per frame, or quantizing countdown timers of how many frames to wait to go to the next state.

Actually, modern (and not so modern) physics engines as used in games generally use a fixed time delta for each step, and just iterate faster/slower to keep the simulation in sync[1]. This is done for many reasons, but predominantly numerical stability.

[1] not the full story

Re: A Comprehensive Super Mario Bros. Disassembly

#47

Earlier quoted context omitted.

Lookup tables were indeed a common technique used by games in the past.

And present, too, right? It's not the same reason as it would have been in the 80s, but today in performance critical code it is not uncommon to reduce the number of conditionals for better CPU pipelining, and lookup tables are a very common tool for this.

Yes I recall a Forza motorsport physics guy saying they used a simple lookup table for the chart which holds the curve for the limit if grip on a tyre. Beats the crab out if calculating it every time.

Re: A Comprehensive Super Mario Bros. Disassembly

#48
post #32

Earlier quoted context omitted.

And present, too, right? It's not the same reason as it would have been in the 80s, but today in performance critical code it is not uncommon to reduce the number of conditionals for better CPU pipelining, and lookup tables are a very common tool for this.

> it is not uncommon to reduce the number of conditionals for better CPU pipelining, and lookup tables are a very common tool for this. On modern CPUs, data dependency, such as lookup tables often cause pipeline stalls — worse pipelining. L1 cache is at a premium as well, you rarely want to waste it to access LUTs. You can compute a lot in 12 cycles caused by L2 hit (L1 miss). In theory up to 32 * 12 = 384 floating p…

To be fair, replacing a series of ALU ops with a lookup table doesn't usually add a "data dependency" - the data dependency probably already existed, but perhaps flowed through registers rather than memory.

What adding a lookup table can do is to add the load-latency to the dependency chain involving the calculation, which seems to be what you are talking about here. For an L1 hit that's usually 4 or 5 cycles, and for L2 hits and beyond it's worse, as you point out. How much that actually matters depends on whether the code is latency-bound and the involved lookup is on the critical path: in many cases where there is enough ILP it won't be (an general rule is that in most code most instructions are not on a critical dependency-chain).

If the involved method isn't that hot then L1 misses (like your example) or worse are definitely a possibility. On the other hand, in that case performance isn't that critical by definition. If the method is really hot, e.g., in a tight(ish) loop, then you are mostly going to be getting L1 hits.

The comparison with 384 FOPs seems a bit off: I guess you are talking about about some 32-FOP per cycle SIMD implementation (AVX512?) - but the assumption of data dependencies kind of rules that out: one would assume it's scalar code here. If it's vectorization, then the whole equation changes!

Re: A Comprehensive Super Mario Bros. Disassembly

#50
post #3

https://gist.github.com/1wErt3r/4048722#file-smbdis-asm-L601... I think this is where the real gems start. The biggest contribution that SMB had was the "physics engine", to retrofit a modern term. The friction, the jumping, the inertia. If you compare it with the primitive physics in Donkey Kong or Mario Brothers, you can really grasp the groundbreaking novelty that was SMB. You can change direction in mid-air, but…

I once read that the way SMB was able to pull off the physics engine on such limited hardware was that it used lookup tables for physics instead of actually calculating velocity. My assembly-fu is weak but it looks like your link is to the section that contains all the lookup tables. I think JumpMForceData for example is a series of offsets for each successive frame after you hit the jump button. https://gist.github.…

The second game, melee, definitely had a more traditional engine running it, too many ~bugs~ fantastic features to have been taking advantage of lookup tables.
Post reply on HN