Author Topic: Retrieving Strings From In-game Chat  (Read 5881 times)

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« on: March 19, 2010, 07:52:01 AM »
OP2 has a way of reading strings for cheat code checking, so I'm wondering if anyone has ever managed to pass text entered in-game into a string inside the .dll, and if they were willing to share the code that does that.
"Nothing from nowhere, I'm no one at all"

Offline Sirbomber

  • Hero Member
  • *****
  • Posts: 3237
Retrieving Strings From In-game Chat
« Reply #1 on: March 19, 2010, 09:46:37 AM »
HFL and/or Forced Exports should be able to do it.  Don't ask me how though.  Never used HFL and never got Exports to work.
« Last Edit: March 19, 2010, 09:46:52 AM by Sirbomber »
"As usual, colonist opinion is split between those who think the plague is a good idea, and those who are dying from it." - Outpost Evening Star

Outpost 2 Coding 101 Tutorials

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #2 on: March 19, 2010, 12:32:22 PM »
I see...

Hooman, I need to know your position  :P


EDIT: I should add that this is an essential component to the Monopoly map. Any roundabout would be just too barbaric and it might slow the map down too much.

The other problem would be that I can't even begin to find my way around the ForcedExports or HFL projects. If no one can write the function I'm looking for, then is anyone willing to teach me how to do it myself?
« Last Edit: March 19, 2010, 03:13:00 PM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #3 on: March 20, 2010, 05:00:44 AM »
Off the top of my head, I'm not sure what to suggest. I've never tried to capture the message you type at the bottom of the screen. I've heard someone else trying to use that for scripting though, and I think with some hacking they got something working (although it may have been awkward).

There are also some keyboard filter things you can use to capture keyboard input. There's a bit about it in the Forced Exports project, but it'd be a chore to use, and wouldn't integrate with the text box at the bottom.

There might be some minor stuff concerning that text box in there too, but not enough to do what you want to do. I guess get out OllyDbg and start exploring that area more.
 

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #4 on: March 21, 2010, 05:00:12 AM »
With all due honesty, Hooman, I have never managed to successfully use a debugger to locate a numeric value, let alone a string/character. That, and I never got a hang of how to use OllyDbg.

I guess locating the string would be the first task. But then a function to pass the values into the .dll would need to be written up, and my basic knowledge of assembly does not allow me to do it.

Don't get me wrong, I will try and maybe even succeed... eventually.

EDIT: My first attempt felt like walking through a maze with 0 light intensity.
Out of sheer luck I managed to locate a couple addresses that may be relevant:
00486659  USER32.GetMessageA
0048665F  USER32.TranslateMessage

I also found two Chat related entries in the lower section of the CPU screen, the one with the HEX dump column.
they be:
004E0F80  ctChatText
004E3E00  TellMeSpecialChatReceived


So, did I rediscover fire, am I actually getting somewhere, or am I looking at the totally wrong place in the totally wrong way?
I used a blank map with a near-blank tech tree in my attempt. I've attached the .dll and tech file, just in case.
« Last Edit: March 21, 2010, 11:00:32 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #5 on: March 21, 2010, 01:18:27 PM »
Ok, first sign of any real progress has finally occurred.

Checked the Memory map whilst running Outpost 2 as an attached process. Whilst scanning through any modules used by Outpost 2, I found something relevant in .data

The data dump at 0054FC50 contains the beginning of the message history displayed in the communications tab.

I was quite happy to notice the following:

at 0054FCF0 fourth column was FE FF FF FF
at 0054FD00 FF FF FF FF | 3C 4E 3E 36 | 3A 20 3A 20 | 36 36 36 00
This translated into <N>6: : 666

Which is my message sent at mark 6.


Now, a message history is probably a very roundabout way of finding strings players enter.

But, this is the best I could find for now, since I am having serious trouble using OllyDbg to find any run time added/modified value.

EDIT: Relating to the message history dump, it seems to come up on a filled space at 00550FF0. So that's probably the end of said message history.


More EDIT:
I seem to have found the dump address for the last message entered.
005756DA.


Another EDIT:
This one came up after I decided to try and check for instructions relating cheat code verification again. At address 00586430 I notice an ESI := [param1] char * chatText instruction.

So far so good, it appears that OP2 uses a chatText char * type variable to handle text entered in that bottom text box.

I'm afraid this is about as far as I can go, since I see nothing I can do to follow a variable.


And another EDIT:
Now I found my way into the names of variables and functions mostly. I actually forgot how I got here, since I'm too tired. Apart from finding a reference to a Player.GetPlayerName() function (which would be a nice addition to the SDK), I located the following:

Code: [Select]
Names in Outpost2, item 2261
 Address=0040FD7C
 Section=.text
 Type=User
 Name=Player.ProcessCommandPacket(CommandPacket *commandPacket):[ctChat]
 Comment=[ctChat]:  EBX := &cp.chatText

By the looks of its location, I have a feeling this will not help me in any way. Can't make much of it either.
« Last Edit: March 21, 2010, 02:37:32 PM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline BlackBox

  • Administrator
  • Hero Member
  • *****
  • Posts: 3093
Retrieving Strings From In-game Chat
« Reply #6 on: March 21, 2010, 02:49:59 PM »
If you want to trap text chat that is typed into the game, the easiest way is going to be by hooking Player.ProcessCommandPacket and checking for ctChat type command packets (those contain the text string that is typed in by the client).

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #7 on: March 22, 2010, 12:32:44 AM »
Hmm, impressive progress. The USER32 functions are not likely what you want, but the ctChatText stuff is relevant.

The USER32 functions are part of the Windows API, and handle "messaging" such as window resizing and display, mouse movement, mouse clicks, and yes, some keyboard events, but they'd be at such a low level as to not be very useful.

The CommandPackets process the player commands. There are a few CommandPacket types you may want to look at, such as:
ctChat
ctChatText
ctChatSFX

I don't remember what the differences are.

You likely want to look into Player.ProcessCommandPacket(CommandPacket* commandPacket). There are sub labels in the OllyDbg file for this function as it is quite large, and quite important. If you check the label for the ctChat case of the "switch" statement (OllyDbg sort of decodes things as such), you will find relevant code. In fact, you will find some rather interesting code. Some interesting code that should give you some space to insert a hook without too much hastle. ;) In fact, the nice thing about inserting code at that point, is it will run symetrically on all machines, so as to allow you to insert "control" function without desyncing the game. Have fun.  :ph34r:
 

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #8 on: March 22, 2010, 07:33:07 AM »
Well, it's nice to know what needs to be done. Found Player.ProcessCommandPacket at 0040E300 in the CPU window.

Now, as for how this should be done, er... I have no idea where to begin.

I'll try to examine that part with OllyDbg some more, but I'm not sure I'll be able to create a code hook myself, not even knowing what a code hook actually does.
« Last Edit: March 22, 2010, 08:09:22 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #9 on: March 23, 2010, 12:02:49 AM »
When the code pane is active, hit Ctrl+<N>, and you'll see a list of names from that module. You can sort the list by the different columns by clicking on them, such as by address, or by (label) name. You can also start typing into the list and it will search for strings with the prefix you're typing.

Find "Player.ProcessCommandPacket", and keep looking through the list until you find the sublabel you want. I formatted the labels as <functionName>:<subLabel>, where subLabel is the particular case of the switch block.


As for code hooks, the easiest case is to find a call instruction you can redirect. Replace the call destination with the address of one of your own functions, and then inside your function, call the original function. Any pre-processing is done before the chained call, and any post-processing will be done after it.

Here's the idea with some untested code. Make sure to replace values in angle brackets with actual values specific to your case. (None of them are meant to be template parameters).
Code: [Select]
; Code sequence to modify
; ... mov/push/etc.
CALL interestingFunction; Encoded such as E8 A0661700, where E8 represents the CALL, and the remaining 4 bytes are the offset
; <returnAddress> ... more code

Code: [Select]
const void* returnAddress = (void*)<returnAddress>;
const int* callRelativeAddrPtr = (int*)((int)returnAddress - 4); // Look back 4 bytes for the offset part of the call instruction
void* originalFunctionPtr = 0;

// Perform a code overwrite to install our hook
// Note: Might call this from a DLL load event (process attach)
void InstallHook()
{
  // Unprotect section of code at <returnAddress>
  DWORD oldAttributes;
  if (VirtualProtect(callRelativeAddrPtr, 4, PAGE_EXECUTE_READWRITE, &oldAttributes) == 0)
    return;   // Could not unprotect pages. Abort

  // Store the old destination of the call instruction
  // Note: The call operand is an offset relative to the start of the next instruction
  originalFunctionPtr = (void*)(*callRelativeAddrPtr + returnAddress);

  // Replace the address of the call instruction with a pointer to our function
  // Note: The call operand is an offset relative to the start of the next instruction
  *callRelativeAddrPtr = (int)(&HookFunction - returnAddress);
}


// Hook function that wraps around previous call
// Note: Make sure the parameter list and return type matches the function being replaced! Very important or your code will crash when it returns (or tries to access parameters).
<ReturnType> Hook(<paramList>)
{
  // Do any pre-processing here
  // ...

  // Chain to the original function (if desired)
  <ReturnType> retVal = *originalFunctionPtr(<paramList>);

  // Do any post-processing here
  // ...

  // Return the value from the chained function (or a modified value)
  return retVal;
}


// Note: Don't forget the UninstallHook function, which undoes the code modification
// Note: Might call this from a DLL Unload event.
void UninstallHook()
{
  *callRelativeAddrPtr = (int)originalFunctionPtr - returnAddress;
}


Now I'll give you some specific hints for your case. Your hook function will probably have a prototype such as:
Code: [Select]
void HookFunction(char* chatText, int sourcePlayerNum);

You can quite safely drop the call to the original function if this is done the way I'm expecting (at the location I'm expecting).

I trust you're aware of what RETN or RET means? Think what happens if you write an overly complicated function such as the following:
Code: [Select]
void OverlyComplicatedFunction()
{
}

Yep, very important that you let a function like that complete it's work.  :rolleyes:
« Last Edit: March 23, 2010, 12:07:54 AM by Hooman »

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #10 on: April 04, 2010, 11:39:55 AM »
My first attempt at adapting the code resulted in the following:

Code: [Select]
const void* returnAddress = (void*) 0x40FD85;
const int* callRelativeAddrPtr = (int*)((int)returnAddress - 4); // Look back 4 bytes for the offset part of the call instruction
void* originalFunctionPtr = 0;

// Hook function that wraps around previous call
// Note: Make sure the parameter list and return type matches the function being replaced! Very important or your code will crash when it returns (or tries to access parameters).
void Hook (char* chatText, int sourcePlayerNum)
{
    if (chatText == "Test") TethysGame::AddMessage (1, 1, "Well", 0, sndSavant10);
}

// Perform a code overwrite to install our hook
// Note: Might call this from a DLL load event (process attach)
void InstallHook()
{
 // Unprotect section of code at <returnAddress>
 DWORD oldAttributes;
 if (VirtualProtect(callRelativeAddrPtr, 4, PAGE_EXECUTE_READWRITE, &oldAttributes) == 0) //line 31, error
   return;   // Could not unprotect pages. Abort

 // Store the old destination of the call instruction
 // Note: The call operand is an offset relative to the start of the next instruction
 originalFunctionPtr = (void*)(*callRelativeAddrPtr + returnAddress); //line 36, error

 // Replace the address of the call instruction with a pointer to our function
 // Note: The call operand is an offset relative to the start of the next instruction
 *callRelativeAddrPtr = (int)(&Hook - returnAddress); //line 40, error
}

BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
  DisableThreadLibraryCalls(hinstDLL);
  InstallHook();
}
if (fdwReason == DLL_PROCESS_UNLOAD) //line 50, error. Ok, I don't know what it's called
{
     *callRelativeAddrPtr = (int)originalFunctionPtr - returnAddress; //line 52, error
}

    return TRUE;
}

And the following errors:
Code: [Select]
Main.cpp|31|error C2664: 'VirtualProtect' : cannot convert parameter 1 from 'const int *' to 'LPVOID'|
Main.cpp|36|error C2036: 'const void *' : unknown size|
Main.cpp|40|error C2296: '-' : illegal, left operand has type 'void (__cdecl *)(char *,int)'|
Main.cpp|50|error C2065: 'DLL_PROCESS_UNLOAD' : undeclared identifier|
Main.cpp|52|error C2113: '-' : pointer can only be subtracted from another pointer|

The address is the CALL for the function that used to check for cheat codes, since it was the only CALL I could find.
« Last Edit: April 04, 2010, 11:40:35 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #11 on: April 04, 2010, 06:06:35 PM »
Cast the result if needed: "(LPVOID)variableName".
Don't change the type of variable from int* to void*, or you can't perform mathematical operations on it, such as adding a constant byte offset to a pointer. In C++ doing "ptrValue + 1" actually means "ptrValue + sizeof(*ptrValue)", which is a bit nonintuitive.
For line 40, cast the address back to an int, so subtraction works: (int)&Hook
The constant you need is DLL_PROCESS_DETACH, I think.
On line 52, maybe add extra parenthesis around the cast, or check if you've changed variable types.
 

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #12 on: April 05, 2010, 03:28:00 AM »
Ok, I used your points to correct most of the errors, but there's still a problem left.

Code: [Select]
 *callRelativeAddrPtr = (int)((int)&Hook - returnAddress);
brings up the following error:
Main.cpp|40|error C2113: '-' : pointer can only be subtracted from another pointer|

My attempted solution is (int)returnAddress.

But that brings up the foollowing error:
Code: [Select]
Main.cpp|40|error C2166: l-value specifies const object|
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #13 on: April 06, 2010, 01:36:21 AM »
Doh, bad location for "const".

I probably wrote this thinking of address constants:
Code: [Select]
const void* returnAddress = (void*) 0x40FD85;
const int* callRelativeAddrPtr = (int*)((int)returnAddress - 4); // Look back 4 bytes for the offset part of the call instruction
When really that means the pointed to values should be constant. Instead, what I should probably have written is:
Code: [Select]
void* const returnAddress = (void*) 0x40FD85;
int* const callRelativeAddrPtr = (int*)((int)returnAddress - 4); // Look back 4 bytes for the offset part of the call instruction

Or if you're desperate, drop the const all together.


So, C++ syntax for you, read the declarations backwards, (aside from arrays and function pointers which are kind of nested). You want a constant pointer to an int, rather than a pointer to a constant int. Btw, there are 3 ways to write const into a declaration. Can you guess which one means what?
Code: [Select]
const int* a;
int const * a;
int * const a;

It turns out, the first two have identical meaning, in which case the pointed to integer is the constant, but the pointer itself can change. In the second case, the pointer itself is constant, but the value it points to can change. You can also make both of them constant with either of:
Code: [Select]
const int * const a;
int const * const a;

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #14 on: April 06, 2010, 03:38:00 AM »
Going to post a complete update of the code:
Code: [Select]
void* const returnAddress = (void*) 0x40FD85;
int* const callRelativeAddrPtr = (int*)((int)returnAddress - 4); // Look back 4 bytes for the offset part of the call instruction
void* originalFunctionPtr = 0;

// Hook function that wraps around previous call
// Note: Make sure the parameter list and return type matches the function being replaced! Very important or your code will crash when it returns (or tries to access parameters).
void Hook (char* chatText, int sourcePlayerNum)
{
   if (chatText == "Test") TethysGame::AddMessage (1, 1, "Well", 0, sndSavant10);
}

// Perform a code overwrite to install our hook
// Note: Might call this from a DLL load event (process attach)
void InstallHook()
{
// Unprotect section of code at <returnAddress>
DWORD oldAttributes;
if (VirtualProtect(callRelativeAddrPtr, 4, PAGE_EXECUTE_READWRITE, &oldAttributes) == 0)
  return;   // Could not unprotect pages. Abort

// Store the old destination of the call instruction
// Note: The call operand is an offset relative to the start of the next instruction
originalFunctionPtr = (void*)(*callRelativeAddrPtr + returnAddress);

// Replace the address of the call instruction with a pointer to our function
// Note: The call operand is an offset relative to the start of the next instruction
*callRelativeAddrPtr = (int)((int)&Hook - returnAddress);
}

BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
 DisableThreadLibraryCalls(hinstDLL);
 InstallHook();
}
if (fdwReason == DLL_PROCESS_DETACH)
{
    *callRelativeAddrPtr = (int)originalFunctionPtr - returnAddress;
}

   return TRUE;
}

The following three lines return errors:
Code: [Select]
originalFunctionPtr = (void*)(*callRelativeAddrPtr + returnAddress);

*callRelativeAddrPtr = (int)((int)&Hook - returnAddress);

*callRelativeAddrPtr = (int)originalFunctionPtr - returnAddress;
First of those returns error C2036: 'void *const ' : unknown size
The next two return error C2113: '-' : pointer can only be subtracted from another pointer

Now, I can see why the last two return errors, but I am not sure what to do with them. Should I add sizeof(returnAddress)?
The first error, well... I'm not so sure :/

Anything I attempted to fix the errors leads to a game crash at that address.


EDIT: Hooman, think we can find each other on IRC sometime? I'm guessing it would speed the work up, provided we both have enough time. I'm asking you, since you're the most involved in this.
« Last Edit: April 06, 2010, 04:43:21 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #15 on: April 06, 2010, 10:36:45 PM »
Ok, I got it working. Thanks for the pasted update. The reason it crashed, was because the hardcoded address was wrong. If you look way up, the return address is not the address of the CALL instruction. It's the address of the instruction *after* the CALL instruction.

Another point is you can't do your string compare the way it's written. That will actually try to compare the addresses of the two strings, not the strings themselves. What the user types in will go into a buffer allocated by Outpost 2. What you're comparing it against is a string stored in the DLL. They do not have the same address, and so your if statements inside the hook function will never be true. You probably want to use strcmp.


Now the first compiler error you listed seems to be caused by the type of returnAddress. I changed it to an int and everything was fine. Actually, that change fixes the next two problems too. The value is only every being used as an offset in bytes, so it's easier to just declare it as an integer. You get funny semantics when trying to do pointer arithmetic in C++. I would kind of prefer they were just treated as byte addresses (when adding/subtracting from them), but they're not.


This seems like a fairly short and simple example project of a useful mod. I'm thinking of adding this to the SVN. :)
 

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #16 on: April 07, 2010, 02:47:37 AM »
The next instruction address I found is 0x40FD8A. It seems to be the right one.

Have you tested it in the game, as well?
Assuming I made the changes the way you expected them to be, OP2 still crashes and OllyDbg doesn't know how to step into the Hooked function because address 00E84227 is unreadable.

My code currently looks like this:
Code: [Select]
int* const returnAddress = (int*) 0x40FD8A;
int* const callRelativeAddrPtr = (int*)((int)returnAddress - 4); // Look back 4 bytes for the offset part of the call instruction
void* originalFunctionPtr = 0;

// Hook function that wraps around previous call
// Note: Make sure the parameter list and return type matches the function being replaced! Very important or your code will crash when it returns (or tries to access parameters).
void Hook (char* chatText, int sourcePlayerNum)
{
   if (strcmp(chatText, "Ping") != false) TethysGame::AddMessage (1, 1, "Pong", 0, sndSavant10);
}

// Perform a code overwrite to install our hook
// Note: Might call this from a DLL load event (process attach)
void InstallHook()
{
    // Unprotect section of code at <returnAddress>
    DWORD oldAttributes;
    if (VirtualProtect(callRelativeAddrPtr, 4, PAGE_EXECUTE_READWRITE, &oldAttributes) == 0)
    return;   // Could not unprotect pages. Abort

    // Store the old destination of the call instruction
    // Note: The call operand is an offset relative to the start of the next instruction
    originalFunctionPtr = (void*)(*callRelativeAddrPtr + returnAddress);

    // Replace the address of the call instruction with a pointer to our function
    // Note: The call operand is an offset relative to the start of the next instruction
    *callRelativeAddrPtr = (int)((int*)&Hook - returnAddress);
}

BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
    DisableThreadLibraryCalls(hinstDLL);
    InstallHook();
}
if (fdwReason == DLL_PROCESS_DETACH)
{
    *callRelativeAddrPtr = (int*)originalFunctionPtr - returnAddress;
}

return true;
}
« Last Edit: April 07, 2010, 03:04:22 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #17 on: April 07, 2010, 03:26:13 AM »
I committed some working code to SVN. I tested it in game and it works.

Oh, and you should probably update it with some credits to yourself. I was in a hurry when I committed the code and forgot to add a note.


Btw, strcmp is a 3 valued function. Less than (-1), equal to (0), or greater than (1). You don't really want to compare it to false.


As for the rest, I'm not noticing any significant differences. I added a return value to the Install/Uninstall functions to indicate success/failure, but that wouldn't account for any differences since I never used those return values.

Let me know if you spot the difference.
 

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #18 on: April 07, 2010, 04:23:19 AM »
Well, the only files I can read are the .cpp-s, and they don't have the code in them...

I still use Code::Blocks, mostly because I'm used to it, and I know you use MSVC.

EDIT: Yeah, it appears that you forgot to put the main file in there, the MessageHook.cpp (thankfully, Code::Blocks can open MSVC 6 projects)
« Last Edit: April 07, 2010, 04:26:54 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #19 on: April 07, 2010, 11:21:13 PM »
Doh!  :blush:

Fixed.

I thought the commit looked a bit small.
 

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #20 on: April 08, 2010, 03:38:26 AM »
Yes, it works.

I was using returnAddress as an integer pointer, instead of a plain integer.

Thanks you for, well... pretty much doing everything, Hooman.

I'll study the thing a little more. For now, the response message only appears in the message history, so either it gets drawn in the bottom message line before the typed-in message, either it doesn't get drawn at all.
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #21 on: April 08, 2010, 04:01:01 AM »
The typed in message is added to the message log after your response message, so it would get overwritten if it appeared there. The hook was inserted at a place that is doing preprocessing on the message, before it's officially accepted and displayed. You'd want your message to appear after that point, or overwrite the message with the response. ...Kind of like "WOOF! WOOF!" ;)

An alternative would be to remember that something was typed in, but not actually handle it, or at least not give a response message until some time later, like the next invocation of AIProc, or perhaps when a short TimeTrigger fires to deliver the message (although that's probably a bit sick and wasteful).

The easiest way is probably just to overwrite the original string. Just be sure to bounds check any overwriting. I'm not sure how big the buffer is though. Probably just releated to the max size of a command packet. Or perhaps the likely lower limit of how long log messages can be. I think it was around 60 characters, including the time stamp.
 

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Retrieving Strings From In-game Chat
« Reply #22 on: April 08, 2010, 04:17:35 AM »
Yes, I just remembered that the Hook replaces a now unused function that gets processed before the text output.
Overwriting the message would simply mean overwriting chatText. You could also output the original message just before the overwriting, if you want to output both messages.

For now, I'm trying to remember those string functions, because it's the first time I may need them in years.

Oh, by the way. Since code hooks alter the game's memory, what happens when the game crashes? Do the changes remain, are they undone, does the game manage to process DLL_PROCESS_DETACH?
« Last Edit: April 08, 2010, 04:18:58 AM by Hidiot »
"Nothing from nowhere, I'm no one at all"

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Retrieving Strings From In-game Chat
« Reply #23 on: April 08, 2010, 04:23:17 AM »
The changes are made in memory, not on disk. If the game crashes, than the OS just reclaims the memory and the changes are lost. You might find them written to a dump file if the OS produces one, but it won't affect starting the game the next time if that's what you're worried about.