Post subject: Implemented Emulator Scripting (snes9x)
Joined: 12/17/2004
Posts: 99
Location: Karlsruhe, Germany
Example first: $ lua -l obelix
joypad[0]=snes9x.SNES_Y_MASK+snes9x.SNES_RIGHT_MASK

while game.x_pos < 500
do
        snes9x.swig_mainloop(snes9x.TRUE)
end
joypad[0]=0
-> Presses the run key until obelix reaches position 500. (game.x_pos was found automatically via searching and comparing values, see example 3) Example 2:
print(ram_word[4473])
-> prints the current frame counter. Example 3:
        -- Init the search
        s_erg = search.search_ram(ram_word, nil)

        -- Press right all the time
        joypad[0]=snes9x.SNES_RIGHT_MASK

        for i=1,20 do
                -- run for 5 frames
                snes9x.swig_mainloop(snes9x.TRUE)
                snes9x.swig_mainloop(snes9x.TRUE)
                snes9x.swig_mainloop(snes9x.TRUE)
                snes9x.swig_mainloop(snes9x.TRUE)
                snes9x.swig_mainloop(snes9x.TRUE)
                -- Search more
                s_erg = search.search_ram(ram_word, s_erg, function (a,b) return a>b end)
        end

        -- Now we run backwards

        -- Press left all the time
        joypad[0]=snes9x.SNES_LEFT_MASK

        -- Wait 40 frames to be running backwards again
        for i=1,40 do snes9x.swig_mainloop(snes9x.TRUE) end

        for i=1,10 do
                -- run for 5 frames
                snes9x.swig_mainloop(snes9x.TRUE)
                snes9x.swig_mainloop(snes9x.TRUE)
                snes9x.swig_mainloop(snes9x.TRUE)
                snes9x.swig_mainloop(snes9x.TRUE)
                snes9x.swig_mainloop(snes9x.TRUE)
                -- Search more
                s_erg = search.search_ram(ram_word, s_erg, function (a,b) return a<b end)
        end
        print("Search erg: ")
        search.print_search(s_erg)
The result is: > obelix.find_x_counter() Search erg: 152 27648 25600 112 27136 25344 113 106 99 153 108 100 Okay 113 and 153 look like coordinates. While 112 and 152 just seem to be found by looking from the wrong offset. Lets put a watch on it: > while true do print(ram_word[113], ram_word[153]) snes9x.swig_mainloop(snes9x.TRUE) end The result is now that we can play the game and watch the value change in real time. Neat! - So what do we need to do now? - I need someone who has Visual C++ and can compile it for windows. - For those that have linux and lua5.1 it might be possible to just download snes9x.so to try it out: http://studwww.ira.uka.de/~s_franz2/snes9x/snes9x.so Then do: lua -l snes9x To have the search.lua and obelix.lua just apply the diff found below. Else you need to compile snes9x and apply the following patch: http://studwww.ira.uka.de/~s_franz2/snes9x/initial_scripting_with_swig-v5.diff Old instructions follow: -- Hi, I implemented initial scripting support for snes9x via swig/lua plus swig/python, swig/php and swig/perl. It is not yet completely finished, but it was much easier than I thought with the help of swig (www.swig.org). And with swig using for example python instead of lua is just a matter of changing the Makefile! (Set SWIG_PYTHON=1 and comment SWIG_LUA = 1, touch snes9x.i and make again!) This means everyone can use their favorite scripting language with snes9x and is not dependant on lua. The patch is rather small and still one can already change all non-pointer settings. And one can also control the main loop as well as all MovieFunctions and access or change all of main memory. It is however not yet possible to 'hook' somewhere into the code and it will just load Themepark by default ;-). And sorry patch is for unix/linux only at the moment as thats what I'm using. (But if you want to try it out, too, what about downloading some Knoppix DVD and run it from Windows via CoLinux (included) or directly boot it) How to build it: - Install lua5.1 - Install swig either from source or via a package and make sure swig has lua and/or python support. - Get the patch from http://studwww.ira.uka.de/~s_franz2/snes9x/initial_scripting_with_swig-v3.diff Use snes9x-1.43-WIP1-src.tar.gz. (You can get it from one of the mirrors) Unpack it. Build it. - patch -p1 < ../initial_scripting*.diff - ./configure - make If everything was okay you now have snes9x.so for lua and _snes9x.so+snes9x.py for python. To use it do for example the following for python: Python 2.3.5 (#2, Oct 16 2006, 19:19:48) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import snes9x Rate: 48000, Buffer size: 2048, 16-bit: yes, Stereo: yes, Encoded: no Found ROM file header (and ignored it). "THEME PARK" [checksum ok] LoROM, 8Mbits, Type: ROM only, Mode: 20, TV: PAL, S-RAM: 0KB, ROMId: ATQP Company: 67 CRC32: CA0E041C joystick: No joystick found. >>> x = snes9x.MovieInfo() >>> snes9x.S9xMovieCreate("test345.smv", 0x1F, snes9x.MOVIE_OPT_FROM_RESET, x.Metadata, 0) Movie record 1 >>> snes9x.my_mainloop() Or what about the following in php or perl: # php runme.php # perl runme.pl Or another nice example in lua: # lua -l snes9x Rate: 48000, Buffer size: 2048, 16-bit: yes, Stereo: yes, Encoded: no Found ROM file header (and ignored it). "THEME PARK" [checksum ok] LoROM, 8Mbits, Type: ROM only, Mode: 20, TV: PAL, S-RAM: 0KB, ROMId: ATQP Company: 67 CRC32: CA0E041C joystick: No joystick found. Lua 5.1.1 Copyright (C) 1994-2006 Lua.org, PUC-Rio > -- Lets create a new movie > snes9x.S9xMovieCreate("test345.smv", 0x1F, snes9x.MOVIE_OPT_FROM_RESET, snes9x.char_to_wchar(""), 0) > -- We need to convert to wchar_t* as swig does not know that type. Movie record > j=snes9x.uint32Array_frompointer(snes9x.joypads) -- We need a new variable first and need to use this helper functions, but it works. > = snes9x.uint32Array_getitem(j, 0) -- Joypad = 0 0 > -- Lets press and hold START > return snes9x.uint32Array_setitem(j, 0, snes9x.SNES_START_MASK ) > return snes9x.uint32Array_getitem(j, 0) 4096 > -- Okay lets wait 100 frames for our start to be accepted > for i = 1,100 do snes9x.my_mainloop() end > return snes9x.uint32Array_getitem(j, 0) 4096 > snes9x.uint32Array_setitem(j, 0, snes9x. 0 ) > for i = 1,100 do snes9x.my_mainloop() end > snes9x.uint32Array_setitem(j, 0, snes9x.SNES_START_MASK ) > for i = 1,100 do snes9x.my_mainloop() end > -- Okay enough keys pressed lets examine memory > ram=snes9x.uint8Array_frompointer(snes9x.Memory.RAM) > addr = 0x7E8900 - 0x7E0000 -- As RAM is mapped at 0x7E of Memory we need to strip the base address > = snes9x.uint8Array_getitem(ram, addr) > -- Okay we have finished our task, lets save that movie > snes9x.S9xMovieStop(snes9x.FALSE) Movie stop > snes9x.S9xExit() -- I hope you enjoy the scripting engine and comments are appreciated, but now I'm much too tired to write anything more. cu Fabian Author: Fabian Franz <snes9x@fabian-franz.de>
Player (199)
Joined: 12/3/2006
Posts: 151
Although I don't really understand all of the code you posted, I must say this looks really interesting from a TAS perspective. Unfortunately I'm a Windows user so I can't try/use this yet, but I'm really looking forward to a Windows build :)
Former player
Joined: 3/23/2006
Posts: 211
wow, I wish this had been around when I wrote my bot for snes9x (Super Mario Kart). This would have been so much easier. Swig is a pretty cool tool (I used it in college to talk to C with Python - to get around python's Global Interpreter Lock for high perforance computing).
do not forget to *ENJOY THE SAUCE*
Former player
Joined: 3/23/2006
Posts: 211
I would just like to point out that I have applied your diff (by hand) to "snes9x-improvement7-src-unix-dehacked-June20_2k6" to make a python snes9x scripter for Super Mario Kart. And it works. You sir, are a genius.
do not forget to *ENJOY THE SAUCE*
Post subject: Re: Implemented Emulator Scripting (snes9x)
Joined: 11/26/2005
Posts: 285
Fabianx wrote:
Blah blah blah
I think I love you.
Post subject: Re: Implemented Emulator Scripting (snes9x)
Active player (411)
Joined: 3/16/2004
Posts: 2623
Location: America, Québec
Swedishmartin wrote:
Fabianx wrote:
Blah blah blah
I think I love you.
He didn't even wrote that :S
Former player
Joined: 3/23/2006
Posts: 211
I haven't been able to get this to work with snes9x 1.51 though :( EDIT: I now appear to have it working for snes9x 1.51 too EDIT2: But only without joypads (ImportError: ./_snes9x.so: undefined symbol: joypads) EDIT3: I think I've figured out a way to give it fake keyboard input from python, but it'll take me a while to implement it. EDIT4: got keyboard input from python working now If anyone wants the patch for snes9x 1.51, just ask
do not forget to *ENJOY THE SAUCE*
Joined: 12/17/2004
Posts: 99
Location: Karlsruhe, Germany
Huffers wrote:
I haven't been able to get this to work with snes9x 1.51 though :( EDIT4: got keyboard input from python working now If anyone wants the patch for snes9x 1.51, just ask
Just upload it somewhere. Perhaps someones finds it useful. Its always best to upload stuff to somewhere (like your python bot for example) so that someone who stumbles upon it can just use it or learn from it :-). Btw. glad you like it and that the work is actually used ... :-) cu Fabian PS: Looking very much forward to watching your SMK run. Its my favorite game and in 1 hour the BT download will be finally finished.