Massassi Forums Logo

This is the static archive of the Massassi Forums. The forums are closed indefinitely. Thanks for all the memories!

You can also download Super Old Archived Message Boards from when Massassi first started.

"View" counts are as of the day the forums were archived, and will no longer increase.

ForumsCog Forum → New Cog AI Verbs
New Cog AI Verbs
2005-07-11, 12:34 PM #1
for dealing with actor alignment
http://jkhub.massassi.net/forums/viewtopic.php?t=135
Air Master 3D (my iPhone game)
My Programming Website
2005-07-11, 3:22 PM #2
Could you tell me how you are adding verbs? I would love to make some of my own. What are you using to compile it, how are you adding it to the verb list, etc...
This could have some major effects on JK cogging.
Sam: "Sir we can't call it 'The Enterprise'"
Jack: "Why not!"
2005-07-11, 3:46 PM #3
He's adding the code into a disassembled JK.exe and reassembling it.

Sige, any progress on that DLL idea you had? If any at all? It would rock to just be able to throw DLLs into a verbs directory and have them autoload.
Bassoon, n. A brazen instrument into which a fool blows out his brains.
2005-07-11, 3:56 PM #4
Could you walk me through how to do this? I've never disassembled/reassembled a program before and I would love to learn how.
Sam: "Sir we can't call it 'The Enterprise'"
Jack: "Why not!"
2005-07-11, 4:40 PM #5
Assembly is very low level. You'll be moving data between memory addresses manually, shifting bits, etc. If you think COG is hard, you have no idea what assembly is like.

The last EXE I disassembled turned into 260 MB of text. The original EXE was maybe 1.6 MB. Yeah...
Bassoon, n. A brazen instrument into which a fool blows out his brains.
2005-07-11, 6:01 PM #6
Actually I think that cogging is quite easy. I was constantly ahead in my programming class (C++), to the point of getting my own book and teaching my teacher a few things.

I was just asking how Sige is editing the JK code (how to disassemble, where the cog functions are located, what he's changing, etc...)

I'm more than willing to learn if someone is willing to teach me.
Sam: "Sir we can't call it 'The Enterprise'"
Jack: "Why not!"
2005-07-11, 6:16 PM #7
Well I wasn't familiar with your skills, that's why I said "if". My point was just that it isn't easy...I'd teach you, but I don't know how. I'm sure Sige can show you how he did it and where in the ASM code his modifications are, but it's gonna be a bit harder to learn how to modify it.
Bassoon, n. A brazen instrument into which a fool blows out his brains.
2005-07-11, 6:17 PM #8
Well, if I don't try, I'll never learn ;)
Sam: "Sir we can't call it 'The Enterprise'"
Jack: "Why not!"
2005-07-11, 6:20 PM #9
By all means, give it a try! Just trying to point out how difficult it is so you don't set yourself up for failure.
Bassoon, n. A brazen instrument into which a fool blows out his brains.
2005-07-11, 9:37 PM #10
Emon - no progress on the DLL idea, though I'm sure something like that could probably work, in some form or another, but I just haven't tried it yet.


I am mostly using ollydbg for debugging and modifications:
http://www.ollydbg.de/
You might look around for a couple tutorials on using it to create modified exes (saving out your changes, etc.), but it isn't too tough.

Making the thing limit and adjoin limit patches only required changes to code, which is why they are available as a patch instead of a whole exe (I would like to make the cog verbs available as some sort of separate loader instead). The cog verbs required more types of changes. There isn't really enough room in JK.exe for adding a bunch of functions and extending the existing functions that register cog verbs, so I had to add in more room (this is why the exe for this is 1mb larger). To do this I had to add a new code segment to the exe header, which required some looking up in the msdn so I could find a description of the windows PE header structure. So, with that done, I now had an extra mb of space at the end of the exe which would get loaded into memory as code, and this is where I added the new cog verbs.

For the new verbs, I first found where jk registers cog verbs. It has a few functions where it has a long list of verbs being registered (jk just has a function that it calls to associate a function pointer with a verb name). I went to the end of one of these lists of verbs being registered, and added in a CALL instruction that would call a piece of code in my new code segment that registers all the functions I have added (this new registering segment just has a RETN at the end which makes it act as if I had simply inserted the code in the middle of the original registering function). I also had to add in the strings for the new verb names, which I just did in a free spot of my new code segment. For the actual functions associated with these new verbs, I just move down a bit in the code segment and stick them in there. Most of the existing cog verb functions are fairly straightforward, and so I was able to look at them to get an idea as to how they work, and create mine in a similar fashion.

Basically, the cog verbs work like this:
cog verb function is called, with the argument to the function being a pointer to data stored about the calling cog. As needed, functions are called to retrieve parameters passed to the cog verb (with the parameter to these functions being the pointer to the cog data). There are different functions for getting different types of parameters (int, float, etc.). The cogs then tend to do some error checking as appropriate (like check to make sure the thing is an actor, or that a pointer is not null) and proceed to do whatever it is they do. After this is done with, it calls a function to set the return value (if there is a return value, and like with getting parameters, there are different functions for different return types).


Some things to watch out for when trying this stuff:

When you copy code (binary->copy binary/paste binary) keep in mind that offsets tend to get messed up, and so you will have to check them to make sure they don't point to some slightly off position.

In ollydbg, you can save code changes to an exe, but generally it doesn't like it if you do this more than once per debug session, so restart the debug in between making code changes. Also, you can change code in two ways: using the assembler, by double clicking on code in the main window, and by changing the binary data in the memory dump. If you use the assembler, you save changes in the code window, if you do anything else, like copy/pasting binary and editing directly in the memory dump, you need to save in the memory dump window.

Code changes get reset in between debug sessions (whenever you restart the debug), but if you made your changes using the assembler, it ought to keep track of them in the 'patches' window.


I didn't really know any assembly before starting work on the JK thing limit patch, so learning how to do this the hard way is certainly possible, if you have a general idea of what you are doing :)
Air Master 3D (my iPhone game)
My Programming Website
2005-07-14, 2:03 PM #11
Ok, I got the disassembler and I found the cog verb sections like you mentioned. I can see the ascii names and the push/call lines but I'm still not entirely sure what the push does.

So far I've been assuming that it's similar to the call function, but does it also carry data with it? I assume it calls the referenced address and continues the function there?

I was also thinking, if you can add cog verbs by adding them to the end of the code, could you also copy some verbs from MOTS (findsectoratpos and the playeraction message would be VERY helpful in JK) [edit] Ok, after seeing how you do your verbs, and looking at MOTS's findsectoratpos verb, I realize that it would be much harder than I thought. The sector verb in MOTS probably references addresses that don't exist in JK or would be rather hard to find. [/edit]

If possible, could you give me a tutorial on the different parts of 1 cog verb. That way I could use it as a base to understand the rest of the verbs?
Thanks for the help you've given me.
Sam: "Sir we can't call it 'The Enterprise'"
Jack: "Why not!"
2005-07-14, 5:29 PM #12
You can just copy some of the verbs from MotS...for the most part. First off, you have to think about which ones will most likely work if copied; the two AI verbs I added were copied from MotS, and I was pretty certain they would work in JK. FindSectorAtPos would probably work in JK too, though I can't tell for sure by just looking at it (it makes some calls to other functions which may or may not be in JK, but they probably are since JK needs to be able to do the equivalent of FindSectorAtPos anyway). You have to look out for some problems when copying things over. The addresses for the get parameter and set return value functions will be different, and some structures will be different too (some values will be in different locations or missing, depending on what got added in MotS). The best way to deal with this is to look at a similar function that is already in JK to figure out where the differences are. I looked at another similar AI function and was able to get the JK locations for the get parameter / set return value functions as well as figure out which offsets in the different structures in memory would be different (for example, the pointer to the AI data was at +0x278 instead of +0x284 in the thing struct).

PUSH will push the value onto the stack and decrease the stack pointer (ESP), it is used when passing variables to a function that is about to be called. You will see functions add or subtract amounts from ESP, the stack pointer, to either make room for local variables or to take care of adding/removing variables passed to a function.


Here's a rundown of the VectorDot function:
00506610 SUB ESP,18 ; make room for temps (0x18, 24 bytes, or 6 floats)
00506613 LEA EAX,DWORD PTR SS:[ESP] ; eax = pointer to temp vector (LEA stores the address calculated in the second parameter into the first, in this case it is pointless I think since it is just doing eax = esp)
00506617 PUSH ESI ; pushes ESI (just storing it to be popped back to its original state later)
00506618 MOV ESI,DWORD PTR SS:[ESP+20] ; esi = pointer to cog info, which is a parameter to all cog verb functions (ESP+20 because we just pushed ESI (ESP - 4) and we also made room for 24 temp bytes (ESP - 0x18)
0050661C PUSH EAX ; arg2 = pointer to temp vector
0050661D PUSH ESI ; arg1 = pointer to cog info
0050661E CALL JKCogRep.004E26E0 ; get parameter (this function is specific to getting a vector parameter, there are others for other types)
00506623 ADD ESP,8 ; restore stack (8 bytes in params, so add 8), eax = 1 edx = vector param ecx = vector.x (registers can hold return values or just be leftovers from the function called)
00506626 LEA ECX,DWORD PTR SS:[ESP+10] ; address of local temp vector 2 (keeping track of ESP can get confusing since the compiler can mangle things, ie ESP +10 for the second temp vector, rather than ESP+0C due to pushing ESI at 0x00506617)
0050662A PUSH ECX ; arg2 = pointer to temp vector 2
0050662B PUSH ESI ; arg1 = pointer to cog info
0050662C CALL JKCogRep.004E26E0 ; get next param
00506631 FLD DWORD PTR SS:[ESP+10] ; load vector1.y; the FPU works with a stack. FLD pushes the second param onto the top of the stack. (gets confusing now, after 0x00506610 vector1.x was ESP + 0, after 0x00506617 it was ESP + 4, now it is ESP + C due to not adjusting ESP after the last function call)
00506635 FLD DWORD PTR SS:[ESP+C] ; load vector1.x (v1.x, v1.y)
00506639 FMUL DWORD PTR SS:[ESP+18] ; multiply v1.x * v2.x (v1.x * v2.x, v1.y)
0050663D FLD DWORD PTR SS:[ESP+14] ; load vector1.z (v1.z, v1.x * v2.x, v1.y)
00506641 FXCH ST(2) ; exchange the 3rd item on the stack with the top (v1.y, v1.x * v2.x, v1.z)
00506643 FMUL DWORD PTR SS:[ESP+1C] ; multiply v1.y * v2.y (v1.y * v2.y, v1.x * v2.x, v1.z)
00506647 FXCH ST(2) ; exchange the 3rd item on the stack with the top (v1.z, v1.x * v2.x, v1.y * v2.y)
00506649 FMUL DWORD PTR SS:[ESP+20] ; multiply v1.z * v2.z (v1.z * v2.z, v1.x * v2.x, v1.y * v2.y)
0050664D FXCH ST(2) ; exchange (but what for?) (v1.y * v2.y, v1.x * v2.x, v1.z * v2.z)
0050664F FADDP ST(1),ST ; add to the 2nd item, pop the 1st (v1.x * v2.x + v1.y * v2.y, v1.z * v2.z)
00506651 FXCH ST(1) ; exchange (v1.z * v2.z, v1.x * v2.x + v1.y * v2.y)
00506653 ADD ESP,8 ; restore stack, esp = pointer to cog info
00506656 FADDP ST(1),ST ; add (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z)
00506658 PUSH ECX ; pushes ecx, then overwrites the spot on the stack with rval
00506659 FSTP DWORD PTR SS:[ESP] ; arg2 = return value (top of floating point stack gets stored at ESP, then popped)
0050665C PUSH ESI ; arg1 = pointer to cog info
0050665D CALL JKCogRep.004E33C0 ; set return value
00506662 ADD ESP,8 ; restore stack
00506665 POP ESI ; restore esi from 0x00506617
00506666 ADD ESP,18 ; restore stack (temps)
00506669 RETN


I've found it is kind of hard to find references in google for assembly instructions...here is one I just now found for the floating point instruction set:
http://webster.cs.ucr.edu/AoA/Windows/HTML/RealArithmetica2.html
You can probably find all of the assembly instructions if you look hard enough at the Intel or AMD website.

It is harder to follow this stuff because it has been generated by a compiler, and you might notice some of it doesn't really make sense, despite getting the job done.

For now try altering some of the existing functions. Then if you want to add your own, look at the exe I posted, since it already has room for more functions.

Here are some important addresses in the exe I posted:
8f4000 - entry (look here to register more verbs)
8f5000 - sqrt 8f4a00
8f5030 - sin 8f4a08
8f5060 - cos 8f4a10
8f5090 - aigetalignment 8f4a18
8f50E0 - aisetalignment 8f4a28
the second address is where I put the string with the function name

One confusing thing you might run into in some of the functions is something like TEST EAX,EAX followed by JE some_address. This seems to get used a lot to check if a pointer is null, and if so then jump to some other point. CMP is another test function, it really just works a lot like SUB a, b in that it does a subtraction to see if they are equal or not...so you might see it followed by a JNZ (jump if not zero, ie not equal).

Best way to figure some of these things out (which function pointer to use for getting a certain type of parameter or setting a return value) is to look at other functions that have the same parameter or return value types.
Air Master 3D (my iPhone game)
My Programming Website
2005-07-14, 9:57 PM #13
Thanks, that's gonna help a lot.

Now, I'm having one little problem. I can't find a save button :o
Sam: "Sir we can't call it 'The Enterprise'"
Jack: "Why not!"
2005-07-15, 10:02 AM #14
If you are in the code area, highlight your changes, right click, copy to executable->selection. In the new window that pops up, right click and save file. Same thing for if you are in the memory dump (adding strings, whatever you might have changed there). What I have found though is that you have to restart the debug each time you save out a change, or it won't be able to save the 2nd time. (Debug->restart). Keep in mind that this also will reset all of your changes...so if you are worried about losing some changes, select the area, right click, binary->binary copy. Just paste that into a text file somewhere. When you paste it back in (binary->binary paste) make sure you select the entire area you will be pasting into, because it won't paste the entire thing if you don't have enough space selected. It's no big deal if you don't select enough or if you select too much, you can just try again in the first case and in the second nothing will happen beyond the range of the data being pasted.
Air Master 3D (my iPhone game)
My Programming Website
2005-08-04, 6:28 AM #15
Woah...MotS verbs in JK now? This stuff is all a bit over my head, but it would be really nice since aside from the extremely useful verbs in MotS and to a lesser extent colored lighting I really prefer JK as an editing platform.

MotS item and forcepower setups are really clunky...plus a lot of my ideas are blocked by that paranoid model autoreset that happens in multiplayer.

I would really be excited about this!
-El Scorcho

"Its dodgeball time!" -Stormy Waters

↑ Up to the top!