Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
idiot spare time project is right

https://www.youtube.com/watch?v=1X0A4thPzRk

loving around with lua code in gtav and made a murder drone

todo: blockchain and smart contract integration anyone know how to embed bitcoin javascript engines into games

Adbot
ADBOT LOVES YOU

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
i use ~500kwh/month minimum year-round :smithicide:
jesus christ do anything to avoid electric hot water service

Angela Merkle Tree fucked around with this message at 09:53 on Aug 3, 2016

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
no off-peak plans here sadly, at this point i'm even considering a heat-pump water heater

relevant to the thread, i've actually got a lovely home automation/data logging app hooked into some ~smart plugs~ and rf temperature sensors which lets me know how sad to be about my power usage


Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
i've been working on an assembler and debugger for the script vm used in gta san andreas

it can attach to the game process, read/write vm state, and inject/reload new code. i just got a simple ruby -> native instructions -> bytecode compiler pipeline working, so now i can write scripts for the game in ruby, and have them executed as native bytecode inside the game

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice

uncurable mlady posted:

woah

how do you even get started on something like this

i've been meaning to do a proper writeup on how i bootstrapped this, but it went something like:

10 years ago: write gta mods as an idiot teenager to learn how to program

2 years ago: get really fascinated with virtual machines and emulators, realise that the gta script must use a vm of some sort

so i picked up my old compiled gta-script mods and started inspecting the bytecode. the games are old enough that they're well-documented, and rockstar leaked their symbol table in the mobile release so i had a reference of opcodes => names/argument counts

my first tool was a disassembler to turn my mods back into something easily editable, then i wrote an assembler that could recompile it to be byte-for-byte identical

now that i have basic code running in the game, i start reversing the VM itself. i found where the VM structure was in memory by assigning predictable values to global/local variables, then searching the process memory for them using ragweed

once i found the structures, i was able to use vm_read/vm_write to alter the memory from the outside, and i hooked my assembler up to inject code into the VM to test it more quickly (instead of needing to restart the game each time)

the most recent feature was the ruby -> bytecode compiler, which uses ruby's built-in parser to generate s-expressions, then custom code to transform those s-expressions into the ones my assembler uses


for anyone else wanting to get started on poo poo like this, it's best to start with something small and achievable. find a game you like, search it's memory with a debugger, change poo poo and see what happens. heap-spraying a great way to find the parts of memory you care about, so if you can get a game to load external files or set user-controlled values, that's a great start to hacking on it

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice

peepsalot posted:

So you're reversing a proprietary VM? It's not a common scripting language / bytecode like Lua?
yeah, that's right. the gta script runs a complete custom VM and bytecode. it's fairly simple compared to lua, it's about as capable as writing code in assembly for a 16-bit processor would be. you only have global/local variables, and no concept of a user-exposed stack. you can't even officially do dereferencing without abusing the array access operators.

this is an example of the native instructions from my disassembler, each instruction begins with an int16 opcode, then 0 or more typed arguments (addresses and raw bytecode in comments above each line)
code:
(labeldef label_62530)

% 00062530 - d6 00 04 00
(andor ((int8 0)))

% 00062534 - 38 00 02 10 07 04 06
(is_int_var_equal_to_number ((var 1808) (int8 6)))

% 00062541 - 4d 00 01 76 f4 00 00
(goto_if_false ((label label_62582)))

% 00062548 - 04 00 02 64 06 04 01
(set_var_int ((var 1636) (int8 1)))

% 00062555 - ba 00 09 53 57 45 45 54 5f 36 00 05 e8 03 04 02
(print_big ((string8 "SWEET_6") (int16 1000) (int8 2)))

% 00062571 - 50 00 01 e7 5a 01 00
(gosub ((label label_88807)))

% 00062578 - 17 04 04 13
(load_and_launch_mission_internal ((int8 19)))
all the `var` variables go into a global variable space beginning at 0x0. you're expected to allocate this space in your bytecode yourself, otherwise your variables begin to overwrite your code lol

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
i've documented the gta script vm memory and savegame layout and found a way to achieve a sort of "binary compatibility" with saves

the script vm has 200kb of main memory space, with missions and external scripts loaded in dynamically afterwards (in the original script, the missions overlap due to the main code only taking up ~194kb of the 200kb space). when the game is saved, the global variable space and a list of VM thread program counters are serialised into the save


typically, modifying the game script files will break your existing saves, and make new saves incompatible with unmodded scripts. this is because naive compilers will compress the original code to fit in new code at the end of the main memory space. this will result in the PCs in your save pointing to unloaded/misaligned code if the code is modified or removed, causing a crash


i've found a way to craft a compiled file that's "binary-compatible" with original and modded saves by not storing threads executing modded code in the savegame. due to how the cooperative multitasking works, you can patch the end of the main loop to point to code in the last 6kb of the main memory space, while ensuring it will never have it's PC saved in that modded code.


6kb is enough space to implement a loader that can load external scripts into dynamically-allocated memory, avoiding the 200kb main memory limit. we can safely persist new code by patching the savegame routine to trigger the modded threads to save their state into previously-unused global variables, then shut down.

in the gif below, the list of VM threads are shown on the left, with threads executing modded code shown in yellow. when the savegame routine is run, the modded threads change from `.` to `x` as they shut down. once the savegame routine is complete, the patched main loop reloads the modded threads from their saved state.


if you remove a modded script and revert to the game's original script file, the patches to the main loop are removed, and because there are no saved threads running modded code, the save safely reverts to a vanilla unmodded save.

this also means i can continue to develop mods while using the same savegames, as the external code is reloaded in a clean state each time. a version id saved into a global variable allows for rails-like migrations too

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice

klen dool posted:

This is seriously impressive. Have you ever looked at the multi theft auto project?

their work on this is even crazier, they've replaced the built-in script VM with their own lua VM calling the native functions. a lot of the newer script loaders for gta4/5 also just call game functions directly. i've been more interested in exploiting the existing VM, as this works on all platforms the game is released on (years ago, i installed some of my script mods on my modchipped og xbox)

i'm the biggest gta fanboy around and i totally agree they lost their way after san andreas. gta4 got way too serious, and while gta5's single-player has some amazing set-pieces, there's really not much to do on your own. gta online is even more of a squandered opportunity, especially with the ridiculous cost of new in-game content, and the inability to even go on cop rampages without spending hours grinding missions with the worst pubbies of any community i've ever seen

while i haven't looked in gta5 modding much, from what i've seen of how their next-gen script engine extends to multiplayer, it's no surprise cheating is rampant either. in multiplayer, you can execute injected code on your client, have the effects applied to the client-side versions of other players, and those effects get synced back to the original player :psyduck:

totally agree that saints row is now more gta than gta is. i've recently added array support to the ruby -> bytecode compiler, and used it to start replicating the saints row garage system, where you can just spawn saved cars over and over again

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
i implemented breakpoints and a repl in my gta debugger



the ruby source code for the breakpoint handler looks like this:
code:
  debug_breakpoint = routine(export: :debug_breakpoint) do
    $breakpoint_resumed = 0
    $breakpoint_do_exec = 0
    loop do
      if $breakpoint_halt_vm == 0
        wait(0)
      end
      if $breakpoint_do_exec == 1
        goto(DEBUG_EXEC)
      end
      if $breakpoint_enabled == 0 or $breakpoint_resumed == 1
        break
      end
    end
  end

  debug_exec = routine(export: :debug_exec) do
    # REPL input code gets JIT'd into here:
    emit(:Rawhex,["B6","05"])
    emit(:Padding,[128])
    goto(DEBUG_BREAKPOINT)
  end
any code inside the VM can execute `gosub(debug_breakpoint)`, which will enter a tight loop and wait for the debugger to break it out by setting `$breakpoint_resumed = 1`. from there, the debugger can also accept input and evaluate code in a single-step mode using a JIT code injector from the breakpoint

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
i accidentally did something dumb with my nier:automata saves and needed to start over from scratch, but the cool combat skills are gated behind upgrade chips you don't get until later in the game. spent a few hours pissing around with the saves and a hex editor, documented the savegame structures, and made a simple editor in javascript



as much as i love to poo poo on javascript, inside a modern browser with file + binary blob apis, it's quite powerful and fast to prototype with. i knew nothing of the apis and still got this running in about 90 minutes

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
i've continued hacking on the gta:sa script vm, and got some pretty powerful tools built for it


first up, there's the script injector and reloader. it acts like the ruby `guard` program and monitors a directory of script files. when you save a script from your editor, it compiles the script and injects or reloads it. by keeping the symbol list from earlier compiles, it's able to patch the old code's jumps to point to the new code, retaining local variable values.

below i'm editing the script to change the text colour from red to green, but the `counter` local variable retains it's value by patching the running code to jump to the updated code



next up is the "JIT compiler" (not entirely sure if it meets the standard definition of it). using a small host script injected into the game vm, it's able to evaluate injected instructions and provide return values. using ruby's `method_missing` i made an opcode proxy object that can directly call vm opcode functions from native ruby code:



finally, i patched the ui framework i was using to achieve higher framerates, and made this giant monstrosity of a visual debugger for it. it uses some of the exotic console input modes to get scroll/cursor support, and has an interactive ruby console hooked up to the opcode proxy available:

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
thanks for the responses, i'm really proud of what it's capable of now. it's been a great learning experience since i don't really have much familiarity with compilers or low-level programming before this.

meatpotato posted:

Is your code posted online? I'd love to peek at it, despite knowing basically no ruby.
the code is a real mess, since this was very much a learn-as-you-go project, but i've got it up a github repo here: https://github.com/lmc/gta-scm
currently only works with the osx steam version of san andreas, but if you've got a recent version of ruby and bundler installed, you should be able to clone it, `bundle install`, and start using the example scripts in /bin

the key files are:
process.rb - attaches to the game process and read/writes the script vm structures
repl.rb - sets up the interactive ruby environment and injects code to evaluate into the game
ruby_to_scm_compiler.rb - a horrible travesty of a s-expression transformer, turning ruby expressions into assembly tokens
assembler.rb - assembles binary scripts from tokens

echinopsis posted:

from a code point of view, is gta quite an achievement or
i touched on it's script virtual machine in an earlier post, but the tldr; is it's a cooperatively-multitasked virtual machine executing custom bytecode, which segues nicely into...

Sagebrush posted:

as someone whose programming experience is almost exclusively with embedded microcontrollers and other small physical devices, the scope of something like that is just mind-boggling. the concept of hooking into someone else's running code and interacting with it in real time is total :aaaaa: *10000000
funny you say that, the vm is only about as capable as most microprocessors (16-bit memory space, ~200kb rom, 48kb ram). you could potentially debug them in a similar manner with a hardware debugger or monitor rom that can read/write memory and registers.

the real secret sauce is generating and caching the symbol lists from the compiler, so you know where your jumps are to patch them later. having a disassembler that can read from live memory helps heaps to debug this.

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
If you're on Windows, Hex Workshop can load up struct definitions from C header files, so you could describe your potential data structures like that and get a formatted view of them like that.

I've managed to support function calls with arguments and return values in my GTA-Script compiler, despite the VM not actually having a stack for data. You just use global/static variables inside the function, then describe how to map arguments/return values to/from them in the method definition, like so:

code:
linear_interpolation = function(args: [$lerp_coords1,$lerp_coords2,$lerp_value], returns: [$lerp_coords3]) do
  $lerp_coords3.x  = $lerp_coords2.x
  $lerp_coords3.y  = $lerp_coords2.y
  $lerp_coords3.z  = $lerp_coords2.z
  ...
end
When the function is called, the compiler generates variable reassignment instructions before gosub-ing to the code:

code:
interpolated_coords = linear_interpolation(player_coords, 0.0,0.0,0.0, 0.75)
results in:

code:
% assign arguments to static variables used by function
(set_var_float_to_lvar_float ((var lerp_coords1_x) (lvar 0 player_coords_x)))
(set_var_float_to_lvar_float ((var lerp_coords1_y) (lvar 1 player_coords_y)))
(set_var_float_to_lvar_float ((var lerp_coords1_z) (lvar 2 player_coords_z)))
(set_var_float ((var lerp_coords2_x) (float32 0.0)))
(set_var_float ((var lerp_coords2_y) (float32 0.0)))
(set_var_float ((var lerp_coords2_z) (float32 0.0)))
(set_var_float ((var lerp_value) (float32 0.75)))

% gosub to function code
(gosub ((label routine_linear_interpolation)))

% re-assign static return variables to local variables
(set_lvar_float_to_var_float ((lvar 3 interpolated_coords_x) (var lerp_coords3_x)))
(set_lvar_float_to_var_float ((lvar 4 interpolated_coords_y) (var lerp_coords3_y)))
(set_lvar_float_to_var_float ((lvar 5 interpolated_coords_z) (var lerp_coords3_z)))

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice

meatpotato posted:

Do you mind breaking down that last code block for a rube like me? I honestly have no idea what it does.

From the description, it sounds like you're using registers (stored in static variables), rather than a stack, to pass parameters and return a value. Did I get that right?

yeah, that's right. the scripting vm it's executing in has ~40kb of working memory, which can be used like static variables or registers. since it doesn't have a proper stack for data, the compiler generates the instructions to to set the arguments first, then executes the function, then sets the return variables afterwards.

unfortunately, this does mean i need to make recursive function calls illegal, as the static variable's values would be clobbered if you called the function recursively.

as far as i know, this is actually the first compiler that can support functions with arguments/returns for this vm. there's no built-in support for anything except basic gosubs, so your code and compiler needs to maintain all the cpu/vm state itself

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
i've been learning c++ by integrating the mruby script engine in gtav


right now it gets called on every game tick, and has access to a few of the native engine functions. since the game takes ages to start, i also implemented a script reloader by hitting f11

i'm using a community sdk that lets you hook into the game with c++ code, and mruby makes it easy to call functions in both directions from c++ <-> ruby. up until a week ago i knew nothing about c/c++ and now i've got a basic embedded vm, which i think speaks wonders about how easy it is to integrate mruby

github repo, the two most-interesting files are script.cpp (engine integration) and mruby/bootstrap.rb (sets up the ruby runtime/environment)

Angela Merkle Tree fucked around with this message at 09:36 on Sep 12, 2017

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice

Progressive JPEG posted:

FWIW that code appears to be more C than cpp (if you should be wanting to learn cpp specifically)
yeah to be honest i don't even know the difference at this point, i'm just typing in whatever visual studio tells me to :v: i've never used a proper ide before this either which might have explained my difficulties learning it earlier

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
thanks, i've been over the moon about this too. i'm at the point of auto-generating the glue code for binding native functions to ruby, would it be advisable to dive in the deep end with templates? for now i've just got a ruby script generating the c code.

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
i've been hacking on the odroid-go handheld device, which is using the gnuboy gameboy emulator.

out-of-the-box, neither the emulator nor the device support the gameboy link cable, but i've gotten it semi-working by sending serial data over usb-uart to a host laptop, and proxying data between devices.

i'm quite proud of my hack to get it syncronised: the gameboy serial port acts in a dom/sub mode, and they'll negotiate the dom on connection. but if the proxy host puts each device into sub mode, they'll wait indefinitely for a byte of data without any sync issues.

it's still flakey but i've successfully traded pokemon between devices using it

Angela Merkle Tree fucked around with this message at 12:37 on Oct 21, 2018

Adbot
ADBOT LOVES YOU

Angela Merkle Tree
Jan 4, 2012

the definition of open: "mkdir android ; cd android ; repo init -u git://android.git.kernel.org/platform/manifest.git ; repo sync ; make"
College Slice
Hopefully not too late to the discussion of an interruptible game scripting language, but I've done something similar and was able to brute-force an execution limit into MRuby. I was integrating a script hook into GTAV and wanted to avoid poorly-written scripts from locking up the game (scripts run in the main thread).

MRuby has a `CODE_FETCH_HOOK` macro that's intended to allow you to decrypt encrypted bytecode on-the-fly, but since it gets called on each opcode execution, I had it increment a global C variable and raise an MRuby VM exception if it executed too many in a frame.

If Lua lets you interrupt co-routines from C and has a similar hook, that could be an avenue for it.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply