Seemann Posted December 6, 2006 Share Posted December 6, 2006 (edited) I've decided to create a new topic to collect all examples how to handle GTASA memory via SCM.If you don't understand what is written there, maybe it's not yours. I'll try to explain more things later by editing this post.All codes are written in Sanny Builder v2.99. To get it working, you should download the latest version of SB.http://www.gtaforums.com/index.php?showtopic=211077All codes are tested in San Andreas v1.0 US. Memory addresses could be different in other versions. If something is not working, be sure you use the version I said.1.Now, we have three ways to handle the game memory .1. Initial memory handling way was published in this topicStat opcodes provide limited memory access to locations near the stat pools. It allows to make things like changing the player's money, for example.Advantages:- the only opcode is usingDisadvantages- memory range is very limited, many useful addresses are inaccesible.2. Second way: using the Xieon's patch, that changes three opcodes in gta-sa.exe and provides extremely wide possibilities for game memory handling.DownloadAdvantages:- all game addresses are accessible- possibility to protect a memory region with VirtualProtect to rewrite itDisadvantages- requires exe patching; may not work with different versions (but in fact, I did not see any messages that the patch is working incorrectly).3. Third way: using the SA arrays to get an access to any addresses in range of 0..FFFFFFFF. Initially was posted there.Advantages:- all game addresses are accessible- easy to use- nothing especial required; scm-based solutionDisadvantages- some of addresses still coudn't be rewritable (because of AccessViolation Error).2.For the last way, there are three routines to read/write values to the specified address:(briefly, so far). Memory Handling Routines (san andreas)1 MemoryWrite: write new value with specified length into the memoryParams: 0@ = address; 2@ = new value; 3@ - value length (1, 2, 3, 4)2 MemoryWrite_DWORD: write new DWord value into the memoryParams: 0@ = address; 1@ = new value;3 MemoryRead: read DWord value from the memoryParams: 0@ = address; 1@ = returned value;note that some address could be unreadable/unrewriteable!!!to change such addresses try Xieon's MemPatch: ..\tools\Sa Memory Patch\ //--write specified number of bytes into memory:MemoryWrite 0085: 5@ = 0@0@ /= 40@ *= 4 // memory address0062: 5@ -= 0@ // offset (0, 1, 2, 3) :_GetInitValue // if you specify mem offset in 5@, you're able to gosub heregosub @MemoryRead // get initial value3@ *= 8 // bytes -> bits5@ *= 8dec(3@)for 6@ = 0 to 3@ if 08B6: test 2@ bit 6@ then 08BF: set 1@ bit 5@ // 1 else 08C5: clear 1@ bit 5@ // 0 end inc(5@) // next memory bitend 008A: &0(0@,1i) = 1@ // write new valuereturn//--write 32-bit value into memory-----------:MemoryWrite32bit0@ -= 0xA499600@ /= 4008A: &0(0@,1i) = 1@ return//--read 32-bit value from memory-----------:MemoryRead0@ -= 0xA499600@ /= 4008B: 1@ = &0(0@,1i)return 3.I wrote some examples using these routines . Most of examples were published at gtaf, some of them was out of there.Now, they are: -------------------------------------------------EXAMPLE 1. Make extremely long trains, 15+ carriages!Original (in Russian)Screenshot------------------------------------------------- :LONGTRAINSthread 'TRAINS' for 0@ = -382229 to -382216 wait 0 &0(0@,1i) = #STREAKC end // type0 changed! // load models #FREIGHT.Load #FREIFLAT.Load #STREAKC.Load while true if and Model.Available(#FREIGHT) Model.Available(#FREIFLAT) Model.Available(#STREAKC) then Break end wait 0 end // create train with new carriages 06D8: 1@ = create_train_at 2278.1771 -1144.8823 27.5108 type 0 direction 1 #FREIGHT.Destroy #FREIFLAT.Destroy #STREAKC.Destroy end_thread -------------------------------------------------EXAMPLE 2. New cheats in run-timeOriginal------------------------------------------------- :NEWCHEATS// EXAMPLE 1: TEST 1 key press (space)thread 'CHEATS'0@ = -229908while true008B: 1@ = &0(0@,1i) // get last keypresses0085: 2@ = 1@ div(1@, 0x 1 00) // 1char: 0x100, 2chars: 0x10000: 3chars: 0x1000000mul(1@, 0x 1 00) // same0062: 2@ -= 1@ // get needed number of chars (1)if 2@ == 0x20 // test if it's SPACEthen 03E5: text_box 'CHEAT1'// Cheat activated Breakendwait 1000end// EXAMPLE 2: TEST 2 keys ('NO')0@ = -229908while true008B: 1@ = &0(0@,1i) // get last keypresses0085: 2@ = 1@ div(1@, 0x 1 00 00) // 1char: 0x100, 2chars: 0x10000: 3chars: 0x1000000mul(1@, 0x 1 00 00) // same0062: 2@ -= 1@ // get needed number of chars (2)if 2@ == 0x4e4f // test if player typed NOthen 03E5: text_box 'CHEAT1' // Cheat activated Breakendwait 1000end// EXAMPLE 3: TEST 3 keys ('WOW')0@ = -229908while true008B: 1@ = &0(0@,1i) // get last keypresses0085: 2@ = 1@ div(1@, 0x 1 00 00 00) // 1char: 0x100, 2chars: 0x10000: 3chars: 0x1000000mul(1@, 0x 1 00 00 00) // same0062: 2@ -= 1@ // get needed number of chars (3)if 2@ == 0x574f57 // test if player typed WOWthen 03E5: text_box 'CHEAT1'// Cheat activated Breakendwait 1000end// EXAMPLE 4: TEST 4 keys ('HACK')0@ = -229908while trueif &0(0@,1i) == 0x4841434B // test if player typed HACKthen 03E5: text_box 'CHEAT1' // Cheat activated Breakendwait 1000end// EXAMPLE 5: TEST 5 keys ('SANNY')// test 5th char 's' from address +4b, then test 'anny' from the beginning;// addr keys// -229908: X X X X | -229908: A N N Y// -229907: X X X O -------------------------------------------------EXAMPLE 3. Changing of the local variables of any threadOriginal (in Russian)-------------------------------------------------// ---------------------------------------------// This thread searches the one named TEST// and changes its local variable 10@// ---------------------------------------------:CHANGELOCALVARthread 'CLV'{ 0@ = thread address 1@ = temp}0@ = 0xA8B42C // FIND_THREAD_LOOPwhile true gosub @MemoryRead // 1@ = first active thread if 1@ == 0 then Break // no threads, search failed end 0085: 0@ = 1@ // save the pointer // get thread name magic address div(1@, 8) dec(1@, 1 348 395) { IMPORTANT NOTE: thread names are stored in lowercase registry, so we've to compare it in lowercase as well. SB option 'Case Converting' has to be set to 'As is'! } if &0(1@,1s) == 'test' // check if this thread's name is "test" then // well, we've found it, can do everything with it // 0@ contains that thread address // get address of 10@ inc(0@, 0x3c) // thread locals pool inc(0@, 40) // local var name * 4; i.e. set to 36 to change 9@ // MEMORY WRITE DWORD 1@ = 3333 // new value of thread('test').10@ gosub @MemoryWrite32bit Break // end the LOOP else // no, that thread has another name // check the next one wait 0 end // go to while_beginend// variable changed, end_thread end_thread// ---------------------------------------------// This thread shows a number after 1 sec// after activated. The number is stored in 10@// ---------------------------------------------:TEST1thread 'TEST'10@ = 10000wait 3000054C: use_GXT_table 'POOL'01E3: text_1number_styled 'NUM' 10@ 5000 ms 1 // ~1~end_threadoptimized version of CLV thread (see above):CODE:CLV03A4: name_thread 'CLV'0006: 0@ = 67251:CLV_LOOP008B: 0@ = &0(0@,1i)00D6: if8039: not 0@ == 0004D: jump_if_false @CLV_END0001: wait 0 ms0085: 1@ = 0@0016: 1@ /= 8000E: 1@ -= 13483950016: 0@ /= 4000E: 0@ -= 269679200D6: if05AD: &0(1@,1s) == 'test'004D: jump_if_false @CLV_LOOP// 25 is the local number + 15// i.e. set to 24 to change 9@000A: 0@ += 25// 3333 is a new value of the local0004: &0(0@,1i) = 3333:CLV_END004E: end_thread-------------------------------------------------EXAMPLE 4. Remove the message "To stop Carl..." when the playerfirst time stealing a carOriginal-------------------------------------------------:MSGREMOVE thread 'NOMSG' 0@ = 0xC0BC15 // ADDRESS 2@ = 1 // VALUE 3@ = 1 // LENGTH (Byte) gosub @MemoryWriteend_thread 4.You can grab a main.scm with all examples from here:http://www.mysharefile.com/v/7409206/memhandling.rar.html- Readme included- source includedchanges history:08 Oct 2014:- fixed CODE tags06 Dec 2006:- added link to the Xieon's patch- added optimized version of CLV thread (example #3) Edited October 7, 2014 by Seemann MasterHK 1 Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
ceedj Posted December 6, 2006 Share Posted December 6, 2006 (edited) Excellent post Seemann! I have applied the #2 method (Xieon's Patch) and have gotten it working using the SA loader by op9080 (a C++ hook, and the foundation for SA Studios). Here's the opcode setups: //Xieon's Memory PatchDEFINE_OPCODE(read_mem_addy, 0x00C3, "iii");DEFINE_OPCODE(write_mem_addy, 0x00C4, "iii");DEFINE_OPCODE(virtual_protect_change_at, 0x0181, "iii"); And here's his example from the Read Me that comes with the patch (moon gravity on jumps) theScript << virtual_protect_change_at << 8796548 << 4 << 4;theScript << write_mem_addy << 8796548 << 2 << 0.002;theScript << virtual_protect_change_at << 8796548 << 4 << -1; Two things: 1) On 0181, the last parameter is a float in the example. Though it works now, suppose I use an address that needs an integer? How would I solve this? 2) Maybe add a link to the patch in your first post. My only gripe with the patch method is that you'd have to include it in any mods that use it (is he allowing this? It's not really clear in the Read Me file), and get your end user to patch it. Although nifty that an auto-find and backup were included in the patch. Edited December 6, 2006 by ceedj Link to comment Share on other sites More sharing options...
Seemann Posted December 6, 2006 Author Share Posted December 6, 2006 1) On 0181, the last parameter is a float in the example. Though it works now, suppose I use an address that needs an integer? How would I solve this? sorry, but why do you speak about 0181? This one has all the parameters integer. Do you mean 00C3/00C4? My only gripe with the patch method is that you'd have to include it in any mods that use it (is he allowing this? It's not really clear in the Read Me file), and get your end user to patch it. yes, it's free to distribute, the only you'd have to do is to include Readme.txt with the patch. Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
Bigun Posted December 6, 2006 Share Posted December 6, 2006 Splendid post Seemann! That's nice, modifying thread locals...we can pretty much kiss globals away. O_o Also good for savegame compabillity. Link to comment Share on other sites More sharing options...
ceedj Posted December 6, 2006 Share Posted December 6, 2006 I was in fact refering to 00C4. Whoops. Anyway, sorry for the confusion. I edited my post with the correct data type for 0181. This is what I get for replying to topics with little sleep. Link to comment Share on other sites More sharing options...
Seemann Posted December 8, 2006 Author Share Posted December 8, 2006 (edited) Main.scm Got Cracked! Finally, I figured out a way to run an assembler code from a main.scm without any patches or whatever. From now, we have no limits for the coding ever. It's similar to the CyQ's method of an injection of the asm code to change opcode handlers. I found two opcodes in SA that could make the same function. They are: 0572 and 0A3D. So, how it works. 1. In San Andreas we have 92 cheats. Some of them are null, some are well-known and often used. 2. These opcodes are well known too. 0572 gives to all taxis the nitro, 0A3D makes the prostitutes pay you (it doen't matter, I use 0572). But not anybody knows that this opcodes works as the cheats like. They enables one of the 92 flags and game begins to think that you use a cheat (but without affecting cheats history, only implying what the cheat does). 3. 0A3D referring to the cheat #90, 0572 - cheat #91 4. All the cheats routines addresses are stored as simple Dword values and COULD be changed in run-time via array's method. 5. So, what this code does: it changes 91st cheat routine address with a value INSIDE main.scm (all adresses are well-known). Then we run this cheat and game goes to the address we set, in other words it goes inside main.scm and begins work with the code as with an assembler. Using hex..end struct in Sanny Builder it's possible to execute ANY code you want. Personally I'm not good ASM'er, so my example is a kind of useless (I just give 1000 buxes to the player), but it's only the beginning. Somebody who knows asm well could implement VirtualProtect routine and then we even do not need to patch the game with the Xieon's patch to work with the addresses that have to be protected (a gravity one, for example). The code: // ----------------------------------// Asm code injector// ----------------------------------// set new handler address0@ = -429863&0(0@,1i) = 0xA49960&0(0@,1i) += @__AsmInjection// Run Asm Injection0572: 1// restore handler&0(0@,1i) = 0return:__AsmInjectionhex// here goes ASM code!//My example: Add $1000 to the player moneyB8 E8030000 // mov eax, 100001 05 50CEB700 // add [0xB7CE50], eaxC3 // returnend This code adds 1000 to the value stored at 0xB7CE50 (player.money). Bit useless, but works! Pay attention: that was tested in San Andreas v1.0 US. If you have v1.01 please test if it works. well, well... There's another example: http://sannybuilder.com/files/cheater.rar This mod allows to enable all cheats by pressing Action Key. Edited December 9, 2006 by Seemann renato186a and Bevardisz 1 1 Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
Seemann Posted March 3, 2007 Author Share Posted March 3, 2007 (edited) I could run the VirtualProtect procedure from the main.scm, and now there's no need for the Xieon's patch: we can do the same through the SCM. Worked on US, EUR, GER 1.0 That's the full code how to write the value with the specified length (1,2,4 bytes) to the specified address protected with VP. :MemoryProofWrite3@ == 1jf @_____novp4@ = -429863&0(4@,1i) = 0xA49960&0(4@,1i) += @_____vpsv0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect 4 gap 0 00572: 1gosub @MemoryWrite0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect -1 gap 0 00572: 1&0(4@,1i) = 0end_thread:_____novpgosub @MemoryWriteend_thread:MemoryWrite3@ = -429864&0(3@,1i) = 0xA49960&0(3@,1i) += @_____mwss0052: gap 0 target_address 0@ size 1@ value 2@ gap 0 00A3D: 1&0(3@,1i) = 0return:_____vpsvhex68 F4 3C A4 00 83 3D 84 3C A4 00 FF75 08 FF 35 F4 3C A4 00 EB 06 FF 35 84 3C A4 00 FF 35 80 3C A4 00 FF 35 7C 3C A4 00 FF 15 2C 80 85 00 C3end:_____mwsshex8B 15 7C 3C A4 00 8B 05 84 3C A4 00 83 3D 80 3C A4 00 01 75 03 88 02 C3 83 3D 80 3C A4 00 02 75 04 66 89 02 C3 89 02 C3end It is a thread that executed once and stopped. Place it to your scripts as you did with other threads. When you create it with 004F, pass four parameters to it: create_thread @MemoryProofWrite address (DWORD) size (Byte: 1,2,4) value (DWORD) VirtualProtect (BOOL) then the local variables of the thread will be initialized with these values. The variables as parameters are allowed. If you only need to write values (without the VirtualProtect) use create_thread @MemoryProofWrite address XXXX size XXXX value XXXX VirtualProtect 0 or without VirtualProtect parameter ever Hello, world! Example1. Changing the gravity (the patch example) /with VirtualProtect create_thread @MemoryProofWrite address 0x00863984 size 4 value 0.002 VirtualProtect 1 Compiled SCM and source Example2. Remove annoying message about entering car (from the first post) /without VirtualProtect create_thread @MemoryProofWrite address 0xC0BC15 size 1 value 1 Edited March 4, 2007 by Seemann Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
DexX Posted March 3, 2007 Share Posted March 3, 2007 Seemann, i just want to be sure i understand you correctly, since i'm not a mission coder; Are you saying we can write anywhere in the game's memory, and write any size data? i've been using a modified vorbis dll (by delfi) to load .asi files, which alter the game's memory as i wish @ runtime. could we use this code you posted, along with the "mission pack" method of installing scm mods? if so that would really be sweet.. Link to comment Share on other sites More sharing options...
Seemann Posted March 3, 2007 Author Share Posted March 3, 2007 Are you saying we can write anywhere in the game's memory, and write any size data? The memory address could be any, but the value size could only be 1, 2 or 4 bytes. The asm code there contains something like: cmp size, 1ja @2mov byte ptr [address], valueret:2cmp size, 2ja @4mov word ptr [address], valueret:4mov dword ptr [address], valueret I could implement the BlockWrite routine for writing the data with any size, need that? Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
PLPynton Posted March 3, 2007 Share Posted March 3, 2007 (edited) that is just great. what is missing is a possibility to decompile a game script whenever hex data input is there. or in fact make a way so code written in such a form will could be decompiled and compiled without loosing its functionality. as most of the coders will like to use your work here it will be a big minus if their MOD can not be decompiled back. Edited March 3, 2007 by PLPynton Link to comment Share on other sites More sharing options...
Seemann Posted March 3, 2007 Author Share Posted March 3, 2007 what is missing is a possibility to decompile a game script whenever hex data input is there. No, such possibility is there since v2.98, IIRC. The Sanny Builder console could receive the commands from the input line and you can turn on the option IGNORE_UNKNOWN which allows to decompile almost any protected/broken scm. Read the help files and the console texts Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
PLPynton Posted March 3, 2007 Share Posted March 3, 2007 (edited) i mean that in other way: it is great what you just did! and the SB returns me "Thread not found. Base: 194426. Probably Script.img is broken" edit: i inserted the thread just before mission 0 (added if line that was missing at the beginning), i issued with create_thread @MemoryProofWrite address 0x00863984 size 4 value 0.002 VirtualProtect 1 from mission 0 code is there anything i could forget to switch? Edited March 3, 2007 by PLPynton Link to comment Share on other sites More sharing options...
Seemann Posted March 3, 2007 Author Share Posted March 3, 2007 and the SB returns me "Thread not found. Base: 194426. Probably Script.img is broken" I'm successed to decompile the files with the hex insertions. BTW, there's no way for exact decompiling. The labels (_____vpsv, _____mwss) will disappear as well when you decompile . So, the way for other people is that the author has to include his source with the mod. i issued with create_thread @MemoryProofWrite address 0x00863984 size 4 value 0.002 VirtualProtect 1 cant understand the kind of issue: code doesnt compile or the game crashes? I just do the same and all works fine to me (heh, it's too funny play with gravity=2.0) Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
PLPynton Posted March 3, 2007 Share Posted March 3, 2007 (edited) well, i still can not decompile it but as you say we have to include source ok, not a problem i guess. i do not want to mess up too much: there is a way to place any kind of informations within script after jump command and that information is ignored by the game, while that kind of information can be interpreted by decompiler after it was created by compiler. additional marking of START, END and TXTCODE (3 nops) will be also required for code that is extraordinary when compiling. nop1 for start of code, nop2 for end code and nop3 somewhere in script after jump (to avoid main part consumption). well but that is just an idea and i understand how unnecesary it might be. ignore that please. ignore that, i have had an issue because my game crashed after i quit and dis not want to start again. did because i messed to much in memory. edit: he i can imagine what happens with 2.0, deadly gravity hehe EDIT2: listen, do not ignore that idea with txt code included in main.scm. what if you do that: i can write a mod then mark my code as "SPECIAL" and it decompiles it after all EXACTLY AS SOURCE- with custom labels, globals, and descriptions. you just place text code after jump when our special nop is there (within main.scm code). then decompile using this text and putting it between our 2 special nops. (even using one nop with several parameters). i think people can like have SOURCE after decompiling right? if the game accepts it of course. Edited March 3, 2007 by PLPynton Link to comment Share on other sites More sharing options...
Seemann Posted March 3, 2007 Author Share Posted March 3, 2007 (edited) i think people can like have SOURCE after decompiling right? The decompiler don't even need for the special marks (nops or whatever) in the code to detect if there's an in-built source code. The compiler just adds the source and the offsets where the text has to be insterted and its length at very end of the file. That also save the space. So, the decompiler checks that and inserts this plain text instead of the byte code (it wont even decompile it as there's a source ready-to-go, yes, just skip?). Very easy. But lets imagine: for example, I have two custom threads. I decide to include one of them as source in main.scm. But it uses custom variables and labels from another one. What happen: when the decompiler put the source, it still use such names, but those thread will have another names after the decompiling. So, that source will be uncompilable. And to avoid that is too hard, I think. Ideas? I think the using of such sources for now only necessary for the hex..end construct. I could make the compiler store all the hex insertions offsets and its length to allow then the decompiler parse them and it should solve the problem with the undecompilable sources. added if line that was missing at the beginning For the single ifs there's no need for 00D6. I just save some space in the main.scm Is the compiled scm from the gravity.rar working for you? Edited March 3, 2007 by Seemann Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
SteaVor Posted March 3, 2007 Share Posted March 3, 2007 Excellent work, Seemann, this is really useful and does work flawlessly for me - it even works with my German v1.0 exe! That's so great! What's the best way to read a value from memory now? Link to comment Share on other sites More sharing options...
PLPynton Posted March 3, 2007 Share Posted March 3, 2007 (edited) yes it can be decompiled but that does not proof why it can not on full game script. i see that it does not lead in any good direction, our further discussion about built in source. just forget it. besides from me too: great work, EU 1.0 NoCD works Edited March 3, 2007 by PLPynton Link to comment Share on other sites More sharing options...
Seemann Posted March 4, 2007 Author Share Posted March 4, 2007 What's the best way to read a value from memory now? I will write similar code for reading the data, but still don't know the best way how to pass the variable pointer where the read value will be stored In theory it should be something like: create_thread @MemoryProofRead address XXX size XXX variable_offset 20 And the code stores the value to variable $5. But most likely I will use another way. i see that it does not lead in any good direction, our further discussion about built in source. just forget it. No, that’s good idea. I will implement it for the hex firstly, and when we'll see how that works - for the text sources. Thanks for your feedbacks, guys. Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
Seemann Posted March 4, 2007 Author Share Posted March 4, 2007 (edited) Well, that's it: { ----------------------------------------------------------------- Memory Access Thread to write a value with the specified length to the memory address use create_thread @MemoryProofWrite address X:DWord size X:BYTE value X:DWORD VirtualProtect X:BOOL to read a value with the specified length by the memory address use create_thread @MemoryProofRead address X:DWord size X:BYTE VirtualProtect X:BOOL The read value will be stored to the variable $MEMORY_PROOF_READ The possible Size values: 1 (byte), 2 (word), 4 (dword) The VirtualProtect parameter is optional----------------------------------------------------------------- }:MemoryProofWrite4@ = @MemoryWrite3@ == 1jf @_____novp:_____mpvp5@ = -429863&0(5@,1i) = 0xA49960&0(5@,1i) += @_____vpsv0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect 4 gap 0 00572: run_VPSV 1gosub 4@0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect -1 gap 0 00572: run_VPSV 1&0(5@,1i) = 0end_thread:MemoryProofRead4@ = @MemoryRead2@ == 0jf @_____mpvp:_____novpgosub 4@end_thread:MemoryWrite4@ = -429864&0(4@,1i) = 0xA49960&0(4@,1i) += @_____mwss0052: gap 0 target_address 0@ size 1@ value 2@ gap 0 00A3D: run_MWSS 1&0(4@,1i) = 0return:MemoryRead4@ = -429864&0(4@,1i) = 0xA49960&0(4@,1i) += @_____mrmm02EC: run_MRMM 1 read_address 0@ size 1@hex3D0A008D0100000000 {store_to} 02 $MEMORY_PROOF_READend&0(4@,1i) = 0return:_____vpsvhex68 F4 3C A4 00 83 3D 84 3C A4 00 FF75 08 FF 35 F4 3C A4 00 EB 06 FF 3584 3C A4 00 FF 35 80 3C A4 00 FF 357C 3C A4 00 FF 15 2C 80 85 00 C3end:_____mwsshex8B 15 7C 3C A4 00 8B 05 84 3C A4 008B 0D 80 3C A4 00 83 F9 01 75 03 8802 C3 83 F9 02 75 04 66 89 02 C3 8902 C3end:_____mrmmhex31 C0 BA 78 3C A4 00 89 02 8B 0D 803C A4 00 8B 05 7C 3C A4 00 83 F9 0175 05 8A 00 88 02 C3 83 F9 02 75 0766 8B 00 66 89 02 C3 8B 00 89 02 C3 end{ ---------end of memory access thread----------------------------- } That thread is the more complex way of getting memory access. For some cases you may need for something shorter. Feel free to modify it.Example: decrease a gravity for 5 sec, then restore to normal create_thread @MemoryProofRead address 0x863984 size 4 VirtualProtect 1wait 0create_thread @MemoryProofWrite address 0x863984 size 4 value 0.002 VirtualProtect 1wait 5000create_thread @MemoryProofWrite address 0x863984 size 4 value $MEMORY_PROOF_READ VirtualProtect 1 edit: optimized mrmm edit2: fixed CODE tags Edited October 7, 2014 by Seemann Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
Seemann Posted March 4, 2007 Author Share Posted March 4, 2007 (edited) That's the multiversion of the memory access thread.You could pass two addresses: one for v1, second for v1.01. The code detects what version is running now and works with that correctly.Parameters: create_thread @MemoryProofMultiWrite/Read address for v1.0 (X:DWord) address for v1.01 (X:DWord) size (X:BYTE) value (X:DWORD) VirtualProtect (X:BOOL) { ----------------------------------------------------------------- Memory Access Thread MultiVersion :: supports GTA SA v1 and v1.01 to write a value with the specified length to the memory address use create_thread @MemoryProofMultiWrite address for version1 X:DWord address for version1.01 X:DWord size X:BYTE value X:DWORD VirtualProtect X:BOOL Example: create_thread @MemoryProofMultiWrite address_V1 0xC0BC15 address_V2 0xC0E295 size 1 value 1 to read a value with the specified length by the memory address use create_thread @MemoryProofMultiRead address for version1 X:DWord address for version1.01 X:DWord size X:BYTE VirtualProtect X:BOOL The read value will be stored to the variable $MEMORY_PROOF_READ Example: create_thread @MemoryProofMultiRead address_V1 0x863984 address_V2 0 size 4 VirtualProtect 1 The possible Size values: 1 (byte), 2 (word), 4 (dword) The VirtualProtect parameter is optional----------------------------------------------------------------- }:MemoryProofMultiWritegosub @_____gsvo017@ = @MemoryWrite4@ == 1jf @_____novp:_____mpvp0085: 8@ = 10@(9@,2i)008A: &0(8@,1i) = 14@(9@,2i)005E: &0(8@,1i) += 16@(9@,2i)0052: gap 0 virtual_protect_at_address 0@(9@,2i) size 2@ newprotect 4 gap 0 00572: run_VPSV 1gosub 7@0052: gap 0 virtual_protect_at_address 0@(9@,2i) size 2@ newprotect -1 gap 0 00572: run_VPSV 1&0(8@,1i) = 0end_thread:MemoryProofMultiReadgosub @_____gsvo017@ = @MemoryRead3@ == 0jf @_____mpvp:_____novpgosub 7@end_thread:MemoryWrite0085: 7@ = 12@(9@,2i)008A: &0(7@,1i) = 14@(9@,2i)005E: &0(7@,1i) += 18@(9@,2i)0052: gap 0 target_address 0@(9@,2i) size 2@ value 3@ gap 0 00A3D: run_MWSS 1&0(7@,1i) = 0return:MemoryRead0085: 7@ = 12@(9@,2i)008A: &0(7@,1i) = 14@(9@,2i)005E: &0(7@,1i) += 20@(9@,2i)02EC: run_MRMM 1 read_address 0@(9@,2i) size 2@hex3D0A008D0100000000 {store_to} 02 $MEMORY_PROOF_READend&0(7@,1i) = 0return:_____gsvo018@ = -429566&0(8@,1i) == 4611680jf @_____gsvo012 // 1.0// 9@ = 0 10@ = -429863 12@ = -429864 14@ = 0xA49960 16@ = @_____vpsv 18@ = @_____mwss 20@ = @_____mrmmreturn:_____gsvo012 // 1.01 9@ = 1 11@ = -431117 13@ = -431118 15@ = 0xA4BFE0 17@ = @_____vpsv2 19@ = @_____mwss2 21@ = @_____mrmm2 return:_____vpsv2hex68 74 63 A4 00 83 3D 04 63 A4 00 FF75 08 FF 35 74 63 A4 00 EB 06 FF 3504 63 A4 00 FF 35 FC 62 A4 00 FF 35F8 62 A4 00 FF 15 2C 90 85 00 C3end:_____vpsvhex68 F4 3C A4 00 83 3D 84 3C A4 00 FF75 08 FF 35 F4 3C A4 00 EB 06 FF 3584 3C A4 00 FF 35 80 3C A4 00 FF 357C 3C A4 00 FF 15 2C 80 85 00 C3end:_____mwss2hex8B 15 FC 62 A4 00 8B 05 04 63 A4 008B 0D 63 00 A4 00 EB 12end:_____mwsshex8B 15 7C 3C A4 00 8B 05 84 3C A4 008B 0D 80 3C A4 00 83 F9 01 75 03 8802 C3 83 F9 02 75 04 66 89 02 C3 8902 C3end:_____mrmm2hex31 C0 BA F8 62 A4 00 89 02 8B 0D 0063 A4 00 8B 05 FC 62 A4 00 EB 15end:_____mrmmhex31 C0 BA 78 3C A4 00 89 02 8B 0D 803C A4 00 8B 05 7C 3C A4 00 83 F9 0175 05 8A 00 88 02 C3 83 F9 02 75 0766 8B 00 66 89 02 C3 8B 00 89 02 C3 end{ ---------end of memory access thread----------------------------- } Example: how to remove the message showed when Carl first time stealing a car in the both versions create_thread @MemoryProofMultiWrite address_V1 0xC0BC15 address_V2 0xC0E295 size 1 value 1 Edited October 7, 2014 by Seemann Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
Y_Less Posted March 4, 2007 Share Posted March 4, 2007 (edited) I did post a thing a long time ago on hacking based almost entirely on CyQ's method before the stats method was discovered (using the set_player_handling hack), I even found an unused OpCode on an accessible boundary for the write and another unused OpCode nearby for the read, unfortunately I never got it working, although I never tried amazingly hard, but yeah, I posted what I had in Demarest's mem hacking revisited topic, but well done for getting this working. Also, ceedj, no offence but what's the point of doing that from C++ when you already have a perfectly good handle into memory? Edit, link to my original SA mem hacking stuff: http://www.gtaforums.com/index.php?showtop...dpost&p=3863930 Also, it's great to see people still continuing all the work like this. Edited March 4, 2007 by Y_Less Link to comment Share on other sites More sharing options...
ceedj Posted March 4, 2007 Share Posted March 4, 2007 None taken buddy. As some people know, I am teh suk on memory stuff, so the patch method was a nice, easy way to get what I want. Just recently however, I think I figured out how the function works that op9080 set up for the gravity controls and the various speed/height patches. There was also the issue of controlling it, as with over 100+ keychecks, finding a spot for another one was tricky. Also bear in mind when I started working with these "hooks" I had NO idea how to program with C++. Some would say I still don't; have a look at Spookie's SCM mod thread here somewhere and watch random_download try to explain asm stuff to me. I, of course, failed spectacularly, but that's another story. @Seemann: at the risk of exposing myself further as the true GTAF-Idiot, I have to ask: is the asm code for that (in SB) a "standard" piece of code? In other words, will I just be able to copy that part and just use the "create_thread" command to do my memory stuff? Although I DO use a hook for most of my SA stuff, I can think of a number of situations where I could have more than one running thread (can't do that with the hooks) and I've even tinkered around with a hybrid setup; using the hook for the keys/selection process and using MB/SB for everything else. Just curious. And BTW, AWESOME JOB coming up with this. You people are friggin genuises. Link to comment Share on other sites More sharing options...
Seemann Posted March 5, 2007 Author Share Posted March 5, 2007 (edited) is the asm code for that (in SB) a "standard" piece of code? Yes, but using only the hex insertions is not enough to handle the memory. The whole thread deals with that: one part loads the parameters to the memory, another one runs the asm code. You should copy one of those threads (for v1 only or multiversion thread, as you wish) anywhere to the MAIN and begin to use it with 004F. Btw, I know the way how to check via the scripts if ANY keyboard key is pressed (I mean ANY key except ESC and PrintScreen ones). Other keys could be checked very easy and it removes the 00E1 opcode limit which allows to check only about 20 pre-defined keys. Interested? Edited March 5, 2007 by Seemann Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
ceedj Posted March 5, 2007 Share Posted March 5, 2007 RE: Thread - yeah, that's what I was wondering about. In my case, using the multiversion thread you posted would be better yes. This is probably a few months away (I'm neck-deep in wrapping the second season), but I LOVE getting answers to possible questions early. Makes my life a whole lot nicer in the end. RE: Keypresses - Hmmm. Let's say yes, and we'll see if I can implement it. Is this related to what Y_Less discussed sometime ago about making your own cheats, or something totally different? Thanks for the heads up buddy! Link to comment Share on other sites More sharing options...
Y_Less Posted March 5, 2007 Share Posted March 5, 2007 If you can hook the keypress reader then you can see if a certain sequence of keys is pressed and then act upon it. That action may be something to improve the players stats/situation at that time and it may also display a text box. So yes, creating your own cheats is very possible. You can also do things like text entry and faking GXTs, although I was looking into faking GXTs in SA the other day for unrelated reasons but I'm not sure how to do it atm, it was easy in VC to track down, SA isn't so easy . Anyway, yes, it is possible. Link to comment Share on other sites More sharing options...
Y_Less Posted March 5, 2007 Share Posted March 5, 2007 (edited) SA cheat processor. To prove the point I've written said cheat processor and designed it to be as easy to use as possible. It uses a very slightly modified version of the mem hacking code to allow it to be called directly or through a create_thread, but this is entirely backwards compatible (basically, if you call it via create_thread just do as you normally would, if you create it directly first set 3@ and 4@ to 1 (4@ is the internal marker to return instead of end_thread but 3@ passes that fact in MemoryProofRead as there's one less parameter)). I don't know what Seemann's method of getting the keys is but this just reads a pool of last pressed letters at 0x969110, this means we don't need to save the code as they enter it but does mean it's limited a bit. To create a new cheat simply do: create_thread @CHEAT_PROCESSOR @CHEAT_CODE_LABEL Then create your cheat code at :CHEAT_CODE_LABEL :CHEAT_CODE_LABEL0661: set_cheat_text "ACTIVATE"03E5: show_text_box 'HELP101'return The 0661 OpCode sets the text required to be typed to activate the cheat (the processor reads this itself and acts accordingly). The rest of the section is the code run when the cheat is entered and the return is required instead of an end_thread or other thing. Also note that in your cheat code 7@ 8@ and 9@ are strictly forbidden, using them will break the cheat! The full cheat processor code (including modified SINGLE version memory access code): { ----------------------------------------------------------------- Cheat Processor Thread To create your own thread simply call this, passing the cheat's processing label as a parameter. Then set the first command in the cheat to: 0661: set_cheat_text "<string to trigger the cheat>" (much like a name_thread but for a cheat) This string can be up to 255 characters but must be entirely capital letters, no other characters at all (spaces, numbers etc) Also, your cheat thread must be ended with a return, not an end thread (unless you want it to be fire once only)----------------------------------------------------------------- }:CHEAT_PROCESSOR0085: 7@ = 0@0@ += 0xA49963 // SCM offset + 31@ = 1 // size2@ = 0 // virtual protect3@ = 1 // return, don't endgosub @MemoryProofRead008B: 8@ = $MEMORY_PROOF_READ7@ += 4005A: 7@ += 8@9@ = 0{ 5@ should now hold the length of the string and nothing more I REALLY wish we could do && and >> in SCM maybe this could be converted to ASM for uber ease... Important variables at this point: 0@-6@ - reserverd for processing 7@ - real cheat label 8@ - string length 9@ - old first DWORD of character table Other notes: 9867536 - decimal offset of some character table}:CP_MAIN_LOOPwait 10000@ = 0x9691101@ = 42@ = 03@ = 1gosub @MemoryProofRead803C: $MEMORY_PROOF_READ != 9@jf @CP_MAIN_LOOP 008B: 9@ = $MEMORY_PROOF_READ 1@ = 111@ = 0:CP_STRCMP802D: 11@ < 8@ // (!>=)jf @CP_SUCCESS0@ = 0x969110005A: 0@ += 11@gosub @MemoryProofRead008B: 10@ = $MEMORY_PROOF_READ0085: 0@ = 7@0@ += 0xA4995F // SCM offset - 10062: 0@ -= 11@gosub @MemoryProofRead003C: $MEMORY_PROOF_READ == 10@ jf @CP_FAILURE11@ += 1jump @CP_STRCMP:CP_SUCCESSgosub 7@// Display cheat message03E5: text box "CHEAT1"0@ = 0x96918C1@ = 42@ = 13@ = 04@ = 1// Mark as having cheatedgosub @MemoryProofWrite0@ = 0xBAA472gosub @MemoryProofWrite// Increase cheat count0@ = 0xB790442@ = 03@ = 1gosub @MemoryProofRead008B: 2@ = $MEMORY_PROOF_READ2@ += 13@ = 0gosub @MemoryProofWrite:CP_FAILUREjump @CP_MAIN_LOOP { ----------------------------------------------------------------- Memory Access Thread to write a value with the specified length to the memory address use create_thread @MemoryProofWrite address X:DWord size X:BYTE value X:DWORD VirtualProtect X:BOOL to read a value with the specified length by the memory address use create_thread @MemoryProofRead address X:DWord size X:BYTE VirtualProtect X:BOOL The read value will be stored to the variable $MEMORY_PROOF_READ The possible Size values: 1 (byte), 2 (word), 4 (dword) The VirtualProtect parameter is optional----------------------------------------------------------------- }:MemoryProofWrite5@ = @MemoryWrite3@ == 1jf @_____novp:_____mpvp6@ = -429863&0(6@,1i) = 0xA49960&0(6@,1i) += @_____vpsv0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect 4 gap 0 00572: run_VPSV 1gosub 5@0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect -1 gap 0 00572: run_VPSV 1&0(6@,1i) = 04@ == 0jf @MemoryReturnend_thread:MemoryProofRead5@ = @MemoryRead0085: 4@ = 3@2@ == 0jf @_____mpvp:_____novpgosub 5@4@ == 0jf @MemoryReturnend_thread:MemoryWrite5@ = -429864&0(5@,1i) = 0xA49960&0(5@,1i) += @_____mwss0052: gap 0 target_address 0@ size 1@ value 2@ gap 0 00A3D: run_MWSS 1&0(5@,1i) = 0return:MemoryRead5@ = -429864&0(5@,1i) = 0xA49960&0(5@,1i) += @_____mrmm02EC: run_MRMM 1 read_address 0@ size 1@hex3D0A008D0100000000 {store_to} 02 $MEMORY_PROOF_READend&0(5@,1i) = 0return:MemoryReturn0051: return:_____vpsvhex68 F4 3C A4 00 83 3D 84 3C A4 00 FF75 08 FF 35 F4 3C A4 00 EB 06 FF 3584 3C A4 00 FF 35 80 3C A4 00 FF 357C 3C A4 00 FF 15 2C 80 85 00 C3end:_____mwsshex8B 15 7C 3C A4 00 8B 05 84 3C A4 008B 0D 80 3C A4 00 83 F9 01 75 03 8802 C3 83 F9 02 75 04 66 89 02 C3 8902 C3end:_____mrmmhex31 C0 BA 78 3C A4 00 89 02 8B 0D 803C A4 00 8B 05 7C 3C A4 00 83 F9 0175 05 8A 00 88 02 C3 83 F9 02 75 0766 8B 00 66 89 02 C3 8B 00 89 02 C3 end{ ---------end of memory access thread----------------------------- } And a few pointless little 'cheats': create_thread @CHEAT_PROCESSOR @HEALTH_CHEATcreate_thread @CHEAT_PROCESSOR @CAR_CHEAT :HEALTH_CHEAT0661: set_cheat_text "HELLO"0256: player $PLAYER_CHAR definedjf @HEALTH_CHEAT_END03E5: show_text_box 'HELP101' // Respect can be earned be passing certain missions, killing rival gangs members, gaining territory and tagging.08AF: set_actor $PLAYER_ACTOR max_health_to 2550223: set_actor $PLAYER_ACTOR health_to 255 00A0: store_actor $PLAYER_ACTOR position_to 10@ 11@ 12@12@ += 100.000A1: put_actor $PLAYER_ACTOR at 10@ 11@ 12@:HEALTH_CHEAT_ENDreturn// Spawns a car:CAR_CHEAT0661: sat_cheat_text "BURN"0256: player $PLAYER_CHAR definedjf @CAR_CHEAT_END 0247: load_model #INFERNUS038B: load_requested_models:CAR_CHEAT_LOADwait 00248: model #INFERNUS availablejf @CAR_CHEAT_LOAD 00A0: store_actor $PLAYER_ACTOR position_to 10@ 11@ 12@10@ += 5.000A5: 0@ = create_car #INFERNUS 10@ 11@ 12@0249: release_model #INFERNUS:CAR_CHEAT_ENDreturn; IMPORTANT (AGAIN): DO NOT USE 7@, 8@ OR 9@ IN YOUR CODE! PS: Seemann, after reading your code I learnt about the missing if statement trick for 1 big statements, cheers. Edit: added a bit to the success label, they now behave exactly like real cheats, including displaying the text box and making the game complain when you try save . Edit 2: do you think you could modify these so the initial writing installs the ASM over existing unused OpCodes, instead of reusing existing one. Obviously use that initially but then have that write other OpCode pointers to point at the data so writing memory becomes as easy as: 0D1E: write_memory 0x01234567 size 1 data 0@ protect 1 01DF: 0@ = read_memory $SOME_LABEL size 4 protect 0 (0D1E is my example unknown OpCode for obvious reasons ) Shouldn't be too hard to fake the correct OpCode code syntax (that's what I was trying to do originally). Plus it shouldn't be too hard to adjust based on the EXE if you know a constant address in both to use and an address different on both to tell which they're using. Edited March 6, 2007 by Y_Less Link to comment Share on other sites More sharing options...
Seemann Posted March 7, 2007 Author Share Posted March 7, 2007 (edited) Is this related to what Y_Less discussed sometime ago about making your own cheats, or something totally different? No, it's nothing about cheats (essentially, I posted my way of the cheats creating on the first post). It's a checking of the keypresses via the memory addresses. I will post this later. Edit: custom keypresses you can also do things like text entry and faking GXTs, although I was looking into faking GXTs in SA the other day for unrelated reasons but I'm not sure how to do it atm, it was easy in VC to track down, SA isn't so easy Well, I did that. I have a subroutine to change the existing GXT entries in run-time on my own text. I could post that later too. do you think you could modify these so the initial writing installs the ASM over existing unused OpCodes, instead of reusing existing one If you mean to do that via the mission scripts (like all in this topic), I should say: there IS a possible way to create a fake opcodes handler and add a hundred of the fake opcodes in range of [0A8C .. 0AEF] doing whatever we want (i like the idea with OD1E but sadly thats impossible). Other opcodes could only be changed with the EXE editing, not in run-time. But please say, what actually we get from this? We will force then to reuse the fake opcode handler activation in order the added opcodes to work every time the game loads. Why not use the Xieons patch which added such opcodes then? Btw, I did not change any opcodes in MemoryProof, those 0052 and 02EC are NOPs and I used them only as a good way to load the parameters into the memory (the hex reads the OpcodeParameters[32] array which address is well-known). Also, in addition of using the MemoryProof: the size parameter is not necessary when it is equals to 4. In other words, DWORD size is default. If you get an access without VirtualProtect you may not specify the size parameter as well: create_thread @MemoryProofRead address 100 this will read 4 bytes from the mem addy 100. And dont forget to add a wait command after using 004F in order a new thread to be created immediately. Edited March 7, 2007 by Seemann Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
Y_Less Posted March 8, 2007 Share Posted March 8, 2007 I'm not sure if that whole post was directed at me but anyway. Is this related to what Y_Less discussed sometime ago about making your own cheats, or something totally different? No, it's nothing about cheats (essentially, I posted my way of the cheats creating on the first post). It's a checking of the keypresses via the memory addresses. I will post this later. Edit: custom keypresses You do know that was the point of my whole last post? you can also do things like text entry and faking GXTs, although I was looking into faking GXTs in SA the other day for unrelated reasons but I'm not sure how to do it atm, it was easy in VC to track down, SA isn't so easy Well, I did that. I have a subroutine to change the existing GXT entries in run-time on my own text. I could post that later too. Interesting, I've been doing unrelated work on GXT memory recently and although I've been unable to create my own (for some reason changing the pointer to your own block of CRC names and pointers doesn't seem to work, but changing individual string pointers does, though is obviously less flexible. do you think you could modify these so the initial writing installs the ASM over existing unused OpCodes, instead of reusing existing one If you mean to do that via the mission scripts (like all in this topic), I should say: there IS a possible way to create a fake opcodes handler and add a hundred of the fake opcodes in range of [0A8C .. 0AEF] doing whatever we want (i like the idea with OD1E but sadly thats impossible). Other opcodes could only be changed with the EXE editing, not in run-time. But please say, what actually we get from this? We will force then to reuse the fake opcode handler activation in order the added opcodes to work every time the game loads. Why not use the Xieons patch which added such opcodes then? CyQs original VC hack thing changed the pointers for two OpCodes, one for read mem, the other for write mem to make them easier to use, plus it's all SCM based, but it's not essential. Btw, I did not change any opcodes in MemoryProof, those 0052 and 02EC are NOPs and I used them only as a good way to load the parameters into the memory (the hex reads the OpcodeParameters[32] array which address is well-known). Also, in addition of using the MemoryProof: the size parameter is not necessary when it is equals to 4. In other words, DWORD size is default. If you get an access without VirtualProtect you may not specify the size parameter as well: create_thread @MemoryProofRead address 100 this will read 4 bytes from the mem addy 100. And dont forget to add a wait command after using 004F in order a new thread to be created immediately. I didn't use create_thread to access memory, I called your functions directly setting the correct locals first (and it does work). Link to comment Share on other sites More sharing options...
Seemann Posted March 8, 2007 Author Share Posted March 8, 2007 You do know that was the point of my whole last post? Well, I think yes You made the SCM-based cheat processor using modified MemProof. But to be fair that differs from the thing I posted there, isn't it? CyQs original VC hack thing changed the pointers for two OpCodes, one for read mem, the other for write mem to make them easier to use, plus it's all SCM based, but it's not essential. That was possible in VS as the opcodes pointers were stored as simple changeable DATA. In SA these pointers are the CODE thing (the part of the exe functions), and they can NOT be changed in run-time, as it is the part of executed code. I didn't use create_thread to access memory, I called your functions directly setting the correct locals first (and it does work). Sure, that’s what I mean when said: you could modify the code to make it simpier and easier in use for your purpose. Sanny Builder 3 • SA Memory Handling • OpenIV • gtamodding.com CLEO.li - The CLEO Library - Official site Link to comment Share on other sites More sharing options...
Bigun Posted April 28, 2007 Share Posted April 28, 2007 Hey (bump!). I've tried to modify the CLV thread to take parameters, so you can easily modify any thread's any local var. Not very surprisingly, it crashes (I'm pretty clueless about anything memory-related ). So I need help with this, and any related info I should know, please. I've narrowed the crash down to the first 008B opcode; I guess it may have to do with that ADMA (&) thing, which I've no idea what I should do with. Took a shot in changing &0 to &3 like the local var, but that wasn't it. Heres the code, including the test thread: :CLV //0@ == thread_name, 1@ == local var num to modify, 2@ value to set to var03A4: name_thread 'CLV' 0006: 3@ = 67251 :CLV_LOOP 008B: 3@ = &0(3@,1i)00D6: if8039: not 3@ == 0004D: jump_if_false @CLV_END0001: wait 0 ms0085: 4@ = 3@0016: 4@ /= 8000E: 4@ -= 13483950016: 3@ /= 4000E: 3@ -= 269679200D6: if05AD: &0(4@,1s) == 0@s004D: jump_if_false @CLV_LOOP//add to 3@ (local var num + 15)000A: 1@ += 15 005A: 3@ += 1@ // integer values // 3333 is a new value of the local//0004: &0(3@,1i) = 3333 //global=int008A: &0(3@,1i) = 2@ // integer values and handles :CLV_END004E: end_thread// -------------------------------------------:debug_var_testthread 'VCHNG'2@ = 2create_thread @CLV thread_name 'vchng' local_num 2 set_value 10wait 2000054C: use_GXT_table 'POOL'01E3: text_1number_styled 'NUM' 2@ 5000 ms 1 // ~1~end_thread Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now