How I Built a Working Online Poker Bot, Part 5: Deciphering Poker Stars and Full Tilt
Thursday, July 17, 2008   

Introduction

Since this series began, I've been asked one question over and over.

How do I build a poker bot for Poker Stars and/or Full Tilt? How do I extract text from the game chat window? How do I snoop on hand history and log files as they're generated?

Today we're going to answer that question.

As of this writing, Poker Stars is the most popular poker venue not only in the world, but in the history of poker. Online or brick-and-mortar, it doesn't matter. There's not currently, and there never has been, another card room in which so many people congregate so routinely to play poker for such sums of money. If you took one of the largest buildings in the world—for example, the Lockheed-Martin manufacturing plant in Fort Worth, Texas...

...and filled it with tables, stretching off into the distance, you'd have yourself a casino which could handle maybe 1% of Poker Stars traffic. Maybe 5% if you pack them like sardines.

With well over 120,000 players at peak hours, Poker Stars isn't really a card room at all.

It's a small city.

Controlled by a mysterious group of investors, operating behind the veil of privacy.

Nothing wrong with privacy; given the politics surrounding online poker, I positively understand it. But in the absence of hard information, rumors abound: Poker Stars is owned by a group of top poker players; a cadre of eccentric billionaires; foreign governments; you name it. I challenge anyone reading this (other than Poker Stars staff and other industry insiders) to answer the question:

Who owns Poker Stars? Who owns Rational Entertainment Enterprises, Ltd.?

Because that's a tough nut to crack, when you're on the outside looking in. And inquiring minds want to know.

Building a Monitor Bot for Poker Stars and Full Tilt

Anyway, we're going to build a little application which is capable of extracting complete table and game information from the Poker Stars client. Hole cards, board cards, player actions, you name it.

We'll call it the "MonitorBot" although it's not technically a bot since this one (unlike last week's FoldBot) doesn't actually click any buttons. Here's what it looks like. Nothing too snazzy as you can see...

Did I mention that one thing today's bot will not do, is click any buttons on your behalf? It's only purpose is to gather information. Because it doesn't automate your play, use of this tool does not constitute a violation of typical online poker EULAs. In fact, all of the information retrieved by this tool can be extracted by publically available tools such as Spy++ and others.

But notice that we're displaying game chat text (in real time) in the top right window, and notice that we're displaying log file text (in real time) in the middle window. Getting access to this text cleanly can be a little tricky. 

The Techniques

Several techniques are demonstrated in today's article. I've broken these out into separate posts.

Then in Part 8 (coming sooner than you think) we'll take these techniques in a direction you might not have anticipated. It should be interesting. Stay tuned.

Running the Poker Stars MonitorBot

In order to run the above application, you'll need to do two things:

  • Download and build the source code (and this time, no Boost libraries! And no NMAKE!)
  • Download and install Poker Stars (www.pokerstars.com) and/or Full Tilt (www.fulltiltpoker.com) and set up a play-money account.

Once you've downloaded and installed Poker Stars, you'll need to set your dealer message verbosity to "Everything" as shown here: 

Repeat the above step on Full Tilt. Then follow these steps to see the MonitorBot in action:

  1. Launch the Monitor Bot executable (XPokerBot.EXE).
  2. Click the "Launch Poker Client" button and browse to the location of the main Poker Stars executable. On most systems, this will be in C:\Program Files\PokerStars\PokerStars.exe. Alternately, browse to Full Tilt.
  3. You should see the Poker Stars client launch. Messages will start to appear in the MonitorBot user interface.
  4. Open one or more Poker Stars game tables. If the tables don't appear in the MonitorBot UI, jiggle the table window by bringing the MonitorBot UI to the foreground, and then bringing the poker table window to the foreground, etc. This is due to a quirk in the underlying Window detection logic.
  5. (Optionally) open the Full Tilt client (FULLTILTPOKER.EXE) using the same "Launch Poker Client" button, and open some Full Tilt tables.

Limitations

The MonitorBot is a demonstrative application, not a working poker bot. As a result:

  • It only works with Texas Hold'em tables on Poker Stars, Full Tilt, and Poker Time.
  • It only works with Windows XP. It may or may not work on Windows Vista.
  • MonitorBot doesn't display hole cards in the UI like the FoldBot did. Instead it demonstrates how to pluck these cards from the log file and/or game text windows.

It's intended to show you techniques which you can use in your own applications, or to serve as a "starter kit" which you can embellish.

Hey! Where are the hole cards?

Different online poker clients emit different information into the game chat window. Some of them, such as Poker Time, display your hole cards in this window; others, like Poker Stars, don't. But in that case they may emit hole cards into the log file (as on Poker Stars) or into the hand history file (as on most poker clients, although there are timing issues).

And in any case, there are other ways to go about getting the hole cards. The point of today's post is to show you one way (out of several) to access the three basic types of text emitted by the client...

  • Game chat window text.
  • Log file text.
  • Hand history text.

Once you have access to that text, what you do with it is up to you.

Building the Source Code

This week's project is much easier to build than the FoldBot we looked at last week.

  • No more Boost! By popular demand, clean regular expressions are gone in favor of low-level, error-prone, but considerably easier-to-build string manipulations.
  • No more NMAKE! This project uses the Detours library, but I've included separate Visual Studio projects for detours.dll and the Detours marker DLL.

So what are you waiting for? Download the MonitorBot source code (C++/Windows 157KB).

Conclusion—Where's the AI?

As interesting as inter-application command and control techniques can be, I think you'll find the A.I. aspects of bot-building even more interesting. We've been busy laying out the framework for the bot's eyes (input) and hands (output) but we'll return to the A.I—the brain—before too long.

For those of you who are new to poker botting, we'll discuss how to build an A.I. from scratch, and we'll talk about how to leverage existing commercial bots as programmatically callable components inside your "master" bot. And whether you're new to poker botting or not, we'll discuss hand evaluation and comparison, game theory and the nuts and bolts of ICM calculation, rules-based vs. heuristic approaches, the importance of table selection, and much more. And at some point we'll say hello to some of the other communities and poker-programming sites that are out there, commercial or otherwise.

Until then, good luck in your poker and programming endeavors.


Posted by James Devlin   113 comment(s)

SEARCH

COMMENTS

Need help! I' m enamored of J.D. Wink!

popo on 7/17/2008 11:09:52 AM (82 days ago)

J.D.: There is a little mistake...in "The Technics" you are linking Part 7 twice.
c u

popo on 7/17/2008 11:47:41 AM (82 days ago)

I am impressed!

Anonymous on 7/17/2008 1:14:10 PM (82 days ago)

Thank you for eliminating the need for NMAKE. It was kicking my butt.

Anonymous on 7/17/2008 1:23:35 PM (82 days ago)

Thank you, looking forward to your next article.

I've compiled, and tested, works like a charm. And just now started meddling with the code. (still have to wrap my head around some c++ it seems)

I'm really looking forward to some robust IPC examples.

Keep up the good work

Nyx on 7/17/2008 1:35:45 PM (82 days ago)

Hmm. Tried this one on Windows XP. I can see the messages pass in the Function Calls window, but I never get the games to show up. I have tried wiggling the windows. Strange.

chipset on 7/17/2008 1:53:04 PM (82 days ago)

finally!!!!!111

Anonymous on 7/17/2008 2:23:00 PM (82 days ago)

So far so good. w00t.

Andrew G. on 7/17/2008 2:43:47 PM (82 days ago)

Great work. That compiled and worked 1st time.
Is there any change of making a .NET managed wrapper of the non C++ peops out here?

Anonymous on 7/17/2008 6:58:21 PM (82 days ago)

You have done an awesome job writing this tutorial! I look forward to your future posts!!!

Paul on 7/17/2008 7:39:16 PM (82 days ago)

Amazing with a capital "A"

It compiled on the 1st try for me too. And ran perfectly, as adverstised (once I identified and found the executable!).

What is the danger of running this in the open? James wrote:

"Because it doesn't automate your play, use of this tool does not constitute a violation of typical online poker EULAs."

but the README file contains...

"Shut down the XPOKERBOT and POKERTIME applications completely before playing real-money online poker."

Anonymous on 7/17/2008 11:41:44 PM (82 days ago)

"What is the danger of running this in the open?"

Only Poker Stars and/or Full Tilt can answer that.

Björn on 7/18/2008 12:50:15 AM (82 days ago)


Not only does MonitorBot work, the source code is a thing of great beauty and precision. It reads like poetry.

James Devlin is for real.

BotEnvy on 7/18/2008 1:10:08 AM (82 days ago)

I agree.

G r e a t E x a m p l e !

Question for anyone who knows:

How would a bot determine player position?
One way that I can think of is reading the previous hand history file, and incrementing the button, but that has some obvious problems, with players leaving, joining, and sitting out, so that can't be it. Thinking out loud... probably by parsing the game chat text, which shows who posts BB and SB, and shows player actions in order. Is that the way to do it?

Also interested in seeing such basics as calculating pot odds, and considering opponent history of loose/tight and pre and post flop aggression

This site delivers

Urbane Plowboy on 7/18/2008 2:21:23 AM (81 days ago)


The one thing that I'm still fairly fuzzy about is how the Global CBT hook relates to detours text extraction. Someone please correct if I'm wrong on this...

The Global CBT hook detecs process windows
The Detours DLL_Process_Attach has nothing to do with that, and will work regardless?

Gamer on 7/18/2008 3:45:25 AM (81 days ago)

@Gamer - in order to extract the text, you have to put your code in the poker client's process. One way to do that is with CBT Hooks; CBT hooks are *also* useful for detecting when a window is created/destroyed. But you could inject the DLL and do the Detour text extraction without the CBT hook if you wanted.

JeremyX on 7/18/2008 8:02:46 AM (81 days ago)

Gr8 with new articles Smile

I tried sending the chat to a simple C# program (redirected the transmittext to send to my own window) the problem i ran into is that i cant seem to decipher this struct:

struct GAME_TEXT
{
GAME_TEXT()
{
::ZeroMemory(this, sizeof(GAME_TEXT));
}

EPokerVenue Venue;
HWND Window;
wchar_t Text[255];
};

into a working C# struct, tried this:

[StructLayout(LayoutKind.Sequential)]
public struct GAMETEXT
{
public int Venue;
public IntPtr Window;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
public string Text;
}

but i only get the first character in the chat... anyone know how to this properly?

H4mm3rHead on 7/18/2008 9:36:57 AM (81 days ago)

Urbane Plowboy wrote:

"interested in seeing such basics as calculating pot odds"

I think that can also be obtained by parsing the game chat text, which details all money put into the pot for each hand. Keep a running total of money in the pot for each hand. The current pot odds would be (total money in pot) / (amount of current bet or raise to you).

another topic would be Reading the Board: Flop, Turn, River
"Texture" of board, possible flush, straight, board pairs, overcards to your hole cards, etc. and then using that info to influence your actions (via some sort of multiplier).

as well as opponent tendencies to play tight or loose, aggressively or passively, steal blinds, defend blinds, continuation bet, etc. etc. etc. (once again via some sort of multiplier, while still evaluating the board)

don't know how much of this sort of thing is necessary or achievable to get winning results, but would be interested in hearing some discussion of the relative importance of some of these types of factors. or is it mostly a case of playing decent cards, in position, with acceptable pot odds?

Twisted Sister on 7/18/2008 11:46:19 AM (81 days ago)

Creating and USING a bot should be done entirely at your own risk. You WILL get caught if you bot and you WILL get banned. It's not really worth the risk. Learn programming skills like this and put it to use for other things, rather than destroying online poker and spoiling the game.

Poker League on 7/18/2008 12:33:13 PM (81 days ago)

H4mm3rhead:

I'm making a wild guess, sounds like your string is terminated by 00 after the first character. So my guess is the text is transmitted as unicode, "abcd" = (65 00 66 00 67 00 68 00) where as the same ansi string is 65 66 67 68.

\00 Null terminated string.

Take this with a big pinch of salt, I'm an amateur mixing/using way to many languages. Perhaps this is not the case in C#

BTW: thanks for that struct layout.

Nyx on 7/18/2008 12:53:18 PM (81 days ago)


"Learn programming skills like this and put it to use for other things"

sounds good to me

League of Independent Screen Scrapers and Hand History Parsers on 7/18/2008 2:07:17 PM (81 days ago)

It should be done entirely at your own risk.. always.. as with anything in life.. but you won't get banned.. you might get a nasty-gram from support.. but if you change the names of the executables.. probably not.. they are only able to identify well-known bots.. which possible the CTW exercises are well-known... who knows.. but in any case.. this bot doesn't violate anything, since it doesn't actually click anything!!

Poker League wrote:

>Creating and USING a bot should be done entirely at your own risk. You WILL get caught if you bot and you WILL get banned. It's not really worth the risk. Learn programming skills like this and put it to use for other things, rather than destroying online poker and spoiling the game.

Puh-leez

JeremyX on 7/18/2008 4:03:13 PM (81 days ago)

For those meddling with the code... I've had a load of stack corruption errors (runtime error #2)
Solution: in gametext.h, increase the size of the text array from 255, to atleast 511 bytes.

Nyx on 7/18/2008 5:42:38 PM (81 days ago)

"For those meddling with the code... "

yes. that would be most of us. as many variations as possible.

Anonymous on 7/18/2008 5:51:53 PM (81 days ago)



==== Go forth, mutate, search and replace, rename, evolve ====

Charlie Darwin on 7/18/2008 6:03:28 PM (81 days ago)

Awesome - thanks for posting the monitor bot source code. Very helpful to us fellow poker bot makers Smile


http://www.icmbot.com

Poker Bots on 7/18/2008 10:47:27 PM (81 days ago)

We will certainly hear more from James about stealth, but it is not too early for us to take basic steps.

It seems that one reasonable precaution is to rename files to more innocuous names than "MonitorBot", "FullTiltPokerClient", "StarsPokerClient", etc. and to do what we can to change file sizes, directory names, icons, etc. You will need to do this carefully before building.

(This is in addition to not botting 24/7)

Barney Rubble on 7/19/2008 1:59:40 AM (80 days ago)

@Nyx

Great that explains a lot, any idea on how to get past that? I could go and change in the C++ files (the original struct) but which datatype should i change it to?

Anonymous on 7/19/2008 4:41:58 AM (80 days ago)

@JeremyX on 7/18/2008 8:02:46 AM (22 hours ago)
(((
@Gamer - in order to extract the text, you have to put your code in the poker client's process. One way to do that is with CBT Hooks; CBT hooks are *also* useful for detecting when a window is created/destroyed. But you could inject the DLL and do the Detour text extraction without the CBT hook if you wanted.
)))
Ok, that is what I thought...Without the CBTHook would it be more difficult to distinguish which table the chat belongs to? Or is this all just done by parent name?

I'm trying to port this to an existing AutoIt hopper, the only thing I really need is the transcript data written to a separate file for each table.

The solution compiled with no errors on the first try with VS2005 btw, that was sweet! Now I'm trying to strip down to barebones minimum dll that just writes to file, and will probably inject using AutoIt...If anyone can offer some advice in this area it would be most appreciated...


Gamer on 7/19/2008 6:23:33 AM (80 days ago)

@Nyx you were right, every other character was a 00 so my app thought it ended there. Made the following tolution if anyone else have the same problem:

Fixed the C# part by creating a struct looking like this:


public struct GAME_TEXT
{
public int Venue;
public IntPtr Window;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=255)]
public char[] Text;
}

and to translate it to a string I made a simple method to help out:

private string ConvertCharArray(char[] input)
{
StringBuilder builder = new StringBuilder();
foreach (char letter in input)
{
if (letter != '\0')
{
builder.Append(letter);
}
}
return builder.ToString();
}


Anonymous on 7/19/2008 6:28:12 AM (80 days ago)

Cheers for the struct definition. Saved me a lot of work Smile

I've semi-succesfully ported the gui to C# now, the problem being when displaying the dealer chat I am getting garbled text at the start of each line:
Àè¤ê54³Ôw0–Dealer: Betting is capped

anyone experienced that?
Could be worked around by only displaying text after the work 'Dealer' - but i dont like that method.

Anonymous on 7/19/2008 4:53:56 PM (80 days ago)

Latest version of PokerStar appears not to include the hole cards in the log file anymore.

Anonymous on 7/19/2008 5:41:42 PM (80 days ago)

Anonymous: I am still seeing the hole cards... was there an update? Anybody else having this problem? If Poker Stars is making software changes based on this blog then... lol. Talk about picking your battles... and where's our author? Sanity check: make sure you're actually logged in and seated at a table....

JeremyX on 7/19/2008 6:52:10 PM (80 days ago)

Still got hole cards in the log.

The garbled text is most likely the pointer pointing (gosh) to the wrong address, in this case to an address 16 bytes before the address of the actual text. Which leads me to believe your pointer has the address of the struct itself and not the text.

You might want to do something like this:
pointer += Marshal.SizeOf(typeof(GAMETEXT)) - 256

Nyx on 7/19/2008 11:54:01 PM (80 days ago)


------------------------------------------------------------------------------------------

You probably already know this, but MonitorBot can serve as the core of an effective data miner. It just needs a parser to extract the desired data on each player observed, and an output to a text file or database. You don't even need to login to use it. It can be totally anonymous if you run it on a PC that you never play poker from.

------------------------------------------------------------------------------------------

Eddie Haskell on 7/20/2008 12:09:14 AM (80 days ago)

@James

Thank you. I feel like the ape in the movie 2001 who touches the obelisk.

Ape on 7/20/2008 2:12:41 AM (79 days ago)

Great writing, great programming. I hope to build a winning "human bot". I will do the clicking.

Agent Provocateur on 7/20/2008 4:11:15 AM (79 days ago)

Has anyone been able to find what writes the player's names and chip counts? I would assume that they are being written as a text somewhere. Are there other system calls that should be monitored here beyond drawText, CreateFile, WriteFile, CreateProcss, and OpenProcess?

Andrew G. on 7/20/2008 11:43:36 AM (79 days ago)

Andrew:
One straightforward way is by reading the hand history file, which is updated to your hard drive after each hand. It shows Seat#, player name, and chip count. The chip count could be kept accurate during the hand, if desired, by using the info from the game chat text.

Bossa Nova on 7/20/2008 1:05:38 PM (79 days ago)

Thanks for the info Bossa! I forgot that you had to toggle saving the hand history in Stars. After watching one hand you should be able to deduce how much a player has in front of them. w00t.

Andrew G. on 7/20/2008 1:31:37 PM (79 days ago)

Yes. As you know, relative stack sizes and the ratio of blinds to stack size are important considerations in modern poker decision making.

The challenge is incorporating this information, along with position, pot odds, opponent tendencies, number of players, board texture, your own cards, etc. in the correct proportions, into an automated winning strategy.

I like the approach here by James Devlin. Teaching and giving excellent examples of the modules necessary to build a winning bot.

Also, the ability to post here anonymously helps people contribute their own ideas.

Bossa Nova on 7/20/2008 3:04:15 PM (79 days ago)

Very interesting.

Btw, is there a reason why XPokerBot.Hook.dll is mapped into the address space of any process? Why not just in that of the poker client?

B. Strider on 7/20/2008 8:30:57 PM (79 days ago)

you can hard code it to the poker client of your choice if you wish

Oscar Mayer on 7/20/2008 8:50:18 PM (79 days ago)

>Need help! I' m enamored of J.D.

Well thanks popo, I ah... have a special someone in my life already, but I appreciate the note. ;) Have you downloaded VS2008 yet?

>Btw, is there a reason why XPokerBot.Hook.dll is mapped into the address space of any process?

No, not really. We're still using the global CBT hook to detect window create/destroy and that injects system-wide but like Oscar said, hard-code it if you wish. Or remove the call to SetWindowsHookEx if you're detecting windows some other way (EnumWindows or something like that).

James Devlin on 7/21/2008 12:33:36 AM (79 days ago)

Hey! Where's the Boost??

I spent 2 wks installing it now you're going to tell me it's gone?? wtf ;)

Anonymous on 7/21/2008 2:41:17 AM (78 days ago)

There is an old saying that "Those who can, do. Those who can't, teach." but James Devlin is a very rare example of someone who can obviously do both. He writes beautiful, well-structured code that works, and explains and illustrates it well. In addition, he has created this environment where we are completely free to ask questions, ranging from the very basic to advanced.

I don't know where this will all lead us, but it is VERY interesting. He is living a dream, and we are all in it.

We who are about to bot, salute you.

Deal Me In on 7/21/2008 2:53:53 AM (78 days ago)

There's so many people wanting to know "who owns PokerStars?!" that your google search turned up exactly one RELEVANT hit in the first couple pages... Smile

Eric on 7/21/2008 6:11:58 AM (78 days ago)

Can someone post a full version of the C# translation? I was going to do this myself but it looks like it's already been done.

JeremyX on 7/21/2008 9:09:56 AM (78 days ago)

What does the "Unglue Windows" button do?

Anonymous on 7/21/2008 7:04:35 PM (78 days ago)

>What does the "Unglue Windows" button do?

Just a convenience feature.

When windows are glued, the (for example) function call window is scrolled downward to show each new line of text as it occurs. Makes it hard to scroll up and see previous lines of text as the location keeps jumping to the bottom. When Windows are unglued, new lines of text are appended but the window isn't scrolled.

James Devlin on 7/21/2008 11:32:49 PM (78 days ago)

Thank you for explaining that. Sounds good. I was afraid to try it, since I did not want to unglue my windows ;)

Anonymous on 7/22/2008 1:19:07 AM (77 days ago)

I like the suggestion that MonitorBot could be used as part of a data miner, without even logging into the site. I think that it could just write the actions to a text file, and very closely approximate the hand histor files generated by the site while dealt into a hand. Does anyone know if it could be modified to mine multiple (up to 10) tables with only 1 instance of MonitorBot running, or would I be forced to run it once for each table that is to be mined? I am a slow programmer, so I would like to have some idea of the feasibility before I start plowing through it.

Miner 49er on 7/22/2008 2:22:38 AM (77 days ago)

@JeremyX
I did some C# stuff, but is relying on the code provided in the monitorbot, i simpley just altered the code to send messages to my C# application instead, and then intercept those and do my own logic. I do not rely on any logic in the injected dll, all logic is done in my C# application. If you (or anyone else) is going down this path, i would be happy to share some code, just tell what you need.

H4mm3rHead on 7/22/2008 10:11:20 AM (77 days ago)

@Miner 49er
Everytime you open a new window you get an event, and everytime anyone at any of the tables you have opened is "talking" (the chat) you are getting a message. So yes! this would indeed be possible, and is even build into the current implementation as far as i can see.

The kind of datamining you are proposing is a "runtime" evaluation of your cards to give instant statistics on how good they are, right? otherwise if you dont need the instant statistics part, it would be better to traverse the log files and make decisions based on those (like AceHUD does)

H4mm3rHead on 7/22/2008 10:17:03 AM (77 days ago)

@H4mm3rHead
As a data miner, I would not need to evaluate the cards on multiple tables in real time. I would just write the actions to text files in the format of the hand history files, which are now only available when dealt into a hand. The HH files that I manufacture from the text control would later be evaluated by PokerTracker, Holdem Manager, or my own application to obtain player stats.

I am optimistic that one instance of a modified MonitorBot could capture text from multiple tables, rather than needing multiple instances of MonitorBot to capture text from multiple tables. The observed resource requirements of MonitorBot (using Windows Task Manager) are very low.

The longer term goal is to incorporate villain characteristics of looseness and aggression into a bot's AI, while not ignoring the other indicators, such as pot odds, position, my own cards, etc.

Miner 49er on 7/22/2008 11:06:53 AM (77 days ago)

@DealMeIn, Nyx, Paul, BotEnvy, Urbane Plowboy, Ape, Agent Provacateur, Anonymous (did I miss anyone?): thanks for the compliments! Too kind. But I reserve the right to produce ugly, bad, evil code and second-rate writing at the drop of a hat.

@Eric: soon to be 2 I hope ;)

@H4mm3rHead: I see you noticed that the C++ code was a little messy, and had no business packaging that stuff into human-readable strings or doing anything but sending the raw data over to the C# app. At the time of posting I could barely hold my eyes open and P/Invoke is a bleak proposition at 3 in the morning, or whatever god-forsaken time of the day it was.

@Eddie Haskell, Miner49er: Yes this code could be turned into a data miner. Slap a few safeguards on it, extract a couple more pieces of information, and you've got everything you need to generate a complete hand history.

@H4mm3rHead: And the only thing about perusing the hand history files (rather than data mining the UI) is that some venues don't generate hand history files unless you're actually seated at the table. Some do. And some used to, but don't anymore.

@Anybody I missed: sorry, I need to get hierarchical comments going here. In the next week or two.

James Devlin on 7/22/2008 11:16:46 AM (77 days ago)

Author wrote: "At the time of posting I could barely hold my eyes open and P/Invoke is a bleak proposition at 3 in the morning, or whatever god-forsaken time of the day it was."

Yeah, that god-forsaken time of day known as: NOON. ;)

(assuming you were in the US of A)

Anonymouse on 7/22/2008 11:43:26 AM (77 days ago)

@H4mm3rHead
Did you figure out
public double[] Limits = new double[2];

BTW the Convert char to string function worked great.

Thanks

LastChance on 7/22/2008 7:31:11 PM (77 days ago)

Ok with the
TransmitText function why is this called again for FTP when the window is brought up.
Example I have the coding wheel app up. I then click over to the ftp game window it seems to send the last 2 lines of chat.

LastChance on 7/22/2008 8:24:46 PM (77 days ago)

Also noticing that transmittext does not get called if the FTP game window has been minamized.

LastChance on 7/23/2008 12:35:49 AM (77 days ago)

@LastChance
I didnt do that one, i only monitor the open and close of windows, and then the chat, i made my own limits decoding function in my C# function. The only thing i do is to detect open and close of window (new table opened) and then i send all the chat to my application. Thats it! then my C# application is in charge of forwarding the chat to the proper table instance in my code to actually do the deciphering. This is much easier for me, since im not that familiar with C++. In regards to your limits problem, i would recon that its the same deal as with the char/string routine you mentionen, just converting it to a double afterwards (so instead of charToString you do char to double)

H4mm3rHead on 7/23/2008 5:49:42 AM (76 days ago)

In regards to multiple tables and forwarding the details back to your C# program for filtering..
How does it work in stars with the log file? I havent quite got to that part yet, is there a seperate file for each table? or does it spam it all into 1? in which case is there a good way of differentiating between tables?

JB on 7/23/2008 5:29:12 PM (76 days ago)

JB, Poker Stars spams everything into the current log file but it emits an 8-character HWND in hexadecimal format indicating the "current" table. You can see these scattered throughout the log.

James Devlin on 7/23/2008 9:26:44 PM (76 days ago)

James maybe you can answer my limit question.
Its not the same as the string one unfortinoatyly because running the program as soon as it trys to cast the struct it gets a error. If I remove the double then there is no issue. Also would you advise doing the button click the same way that you did with pokertime?

Anonymous on 7/23/2008 11:25:10 PM (76 days ago)

Can you tell me where have i put a peace of code in order to save the chat text into a seperate file. The Classname in which i can do this in the xPokerbot sources.

Anonymous on 7/25/2008 7:13:31 AM (74 days ago)

"tell me where have i put a peace of code in order to save the chat text into a seperate file"

I don't know how to do this either, but there should be many examples of writing text files for Vis C++.

Anonymous on 7/26/2008 10:43:46 PM (73 days ago)

H4mm3rHead

Have you been able to convert this function to C#?

PerformAction(HWND hPokerTable)

LastChance on 7/27/2008 5:56:27 PM (72 days ago)

I do not advise you to download executables from unknown sources. You are safer downloading code and building it yourself.

Anonymous on 7/28/2008 12:12:09 AM (72 days ago)

*************************************************************************************************
Beware of PoisonBots that are able to send info on your account name, password, hole cards, and/or current table to a remote location. Download source code only. Look at the code and understand it before you compile and use it. Ask questions.
*************************************************************************************************

Anonymous on 7/28/2008 2:26:32 PM (71 days ago)

>Beware of PoisonBots that are able to send info on your account name, password, hole cards, and/or current table to a remote location.

This is good advice. Never download a botting executable (or any executable) from an untrusted source. Coding the Wheel sample downloads are SOURCE CODE ONLY for this reason. If someone posts a link to a "poker bot" please investigate it before downloading and using it.

James Devlin on 7/28/2008 3:10:56 PM (71 days ago)

Hello all I just built the MonitorBot and the file monitor thingy. I'm seeing some of the poker clients open up some strange files. Stuff in my browser history and so forth, registry entries, and etc. Anybody else seeing the clients opening files they shouldn't be?

Anonymous on 7/29/2008 7:12:58 AM (70 days ago)

no problems for me

Anonymous Too on 7/29/2008 10:50:12 AM (70 days ago)

@LastChance
Yeah i did that one too, i roughly translated the code into my C# application and created this method:


private void PerformButton1Click()
{
Win32.RECT myRect = new Win32.RECT();
Win32.GetWindowRect((IntPtr)table.WindowHandle, out myRect);

float button1XOffset = myRect.Width * 0.34f;
float button1YOffset = myRect.Height * 0.07f;
Point oldPoint = new Point(myRect.Right - (int)button1XOffset, myRect.Bottom - (int)button1YOffset);
Cursor.Position = oldPoint;
Thread.Sleep(200);
Win32.DoMouseClick(oldPoint);
}

I have divided the buttons on the front into 3, button1, button2 and button3 (hence the names). Since the buttons are scaled with the window i have a factor that denotes the distance from the right side or the bottom of the window to the acctual button (the 0.34 * window width is the location of the first button [fold button]). Then i just move the mouse there and simulate a mouse click - works fine Smile

BTW here are the methods and structs:
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;

public int Width
{
get { return Right - Left; }
}

public int Height
{
get { return Bottom - Top; }
}
}
...

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);

private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
//private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
//private const int MOUSEEVENTF_RIGHTUP = 0x10;


public static void DoMouseClick(Point point)
{
//Call the imported function with the cursor's current position
int X = point.X;
int Y = point.Y;
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
}

Hope you get it working, i just got mine up and folding to every bet.. i still struggle though , with how to determine which actions are available to me when its my turn...

H4mm3rHead on 7/29/2008 11:07:49 AM (70 days ago)

TY H4mm3rHead
I think i got something for it btw if you got a way for me to contact you other tahn here let me know.

LastChance on 7/29/2008 11:58:12 PM (70 days ago)

H4mm3rHead

Still don't have this click working right. Is there a reason that you are using thread.sleep?
Also the .34 how did you come across that number?


I was trying this to go through ranges but only seems to work if my curor is actually over the fold button

Single s = 0.34f;
Single x = .32f;
while (x < .35f) {
s = (0.34f + x);
x = x + .01f;
float button1XOffset = myRect.Width * s;
float button1YOffset = myRect.Height * 0.07f;
Point oldPoint = new Point(myRect.Right - (int)button1XOffset, myRect.Bottom - (int)button1YOffset);
//Cursor.Position = oldPoint;
//Thread.Sleep(200);
Debug.WriteLine(x.ToString());
DoMouseClick(oldPoint);
}

LastChance on 7/30/2008 12:59:06 AM (70 days ago)

I think this might actually be missing the mouse move before doing the mouse click. Let me know.

LastChance on 7/30/2008 1:25:54 PM (69 days ago)

@LastChance
The sleep is just to let me see when i click, you can remove it if you want to. The .34 is the ratio to multiply to the windows width. Because the buttons get resized when you resize the window (tiling eg. 4 tables) you eed to get the loctions of the buttons. I simpley just measured how far from the right side the fold button was and then divided by the width of the window and came up with that ratio. You should do a GetWindowRect call to get the location of the table window, then multiply the width with the ratio and subtract it from the right edge.. this should work...

like in my previous example:

float button1XOffset = myRect.Width * 0.34f;
float button1YOffset = myRect.Height * 0.07f;
Point oldPoint = new Point(myRect.Right - (int)button1XOffset, myRect.Bottom - (int)button1YOffset);

H4mm3rHead on 7/31/2008 1:00:19 PM (68 days ago)

Update: This is the best fun ever, got mine working perfectly, gotta do some serious AI though, its not so good at winning Smile


Btw: a cool library for C# poker statistics: http://www.codeproject.com/KB/game/pokerhandevaldoc.aspx

Update: To get the options available to me each tim e its my turn, i modified the xpokerbot dll to not only look at the FTCChat window but also the skinbutton and send me those messages. then its simply just a matter of seeing what they send to me...

H4mm3rHead on 7/31/2008 1:27:41 PM (68 days ago)

So I moved to 64 bit today and now i don't seem to be betting the call backs from the app if anyone has any idease let me know.

LastChance on 8/1/2008 12:27:38 AM (68 days ago)

List of Computer Poker Literature
www.pokerai.org/.../Computer_poker_literature

Anonymous on 8/2/2008 2:51:51 PM (66 days ago)

Perhaps we are missing something, but it seems that Poker Stars has disabled the extended dealer options?

Is anyone else encountering this? It's quite possible that we have misunderstood, but it all compiles and seems to be missing the significant table information (namely the cards). I assume this is because the extended dealer info isn't turned on. Did this get moved somewhere else? Or removed?

Most importantly: how to make the information appear so that we can extract it via the functions?

Him on 8/3/2008 10:55:15 PM (65 days ago)

Poker Stars Hole cards go to the log file
FTP you will see hole cards in the chat window.

LastChance on 8/4/2008 9:57:38 AM (64 days ago)

What are some ways that people are making there bot realize that its there turn to act? My first idea was keep track of who is on your left but this starts to become a mess when people stand up or are not in the hand.

LastChance on 8/5/2008 11:02:06 AM (63 days ago)

@LastChance
Well... i first reacted on the "you have 15 seconds to act" text, but that was too obvious that i was a bot always waiting for that text. I made a temp solution (maybe ill stick with it) i make two things:

* I altered the C++ to also send me all the button activation events (the activated function that informs you that a window have been opened, modify it to also listen for the TC...SkinButtton and transmit that also. This gives you which actions are available to you.

* I made a timer to check every 3 seconds if a special color is present at a special point on the board Smile the fold button will always be active (showing either fold/check). And i simply just check for a blueish color at the point i click it, if i find the color, its my turn Smile

I ran into a different problm though, was trying to do this on another Venue (Ladbrokes) they also transmit the hole cards into chat (and it seems that they have a top level window as chat) But unfortunately i get a lot of exceptions, and i think its related to the fact that thwe window handle is invalid for some reason... it shows only 6 digits not 8 as it is supposed to. Spy++ says its invalid, and the code makes a "memory around variable 'c' is corrupted" in OnlinePokerClient.cpp line 63. Anyone have an idea of what is wrong?

H4mm3rHead on 8/5/2008 11:19:38 AM (63 days ago)

hi,

- ¿Because detoured.dll create your own, because we do not use that comes with Detours ?
- ¿Detourcreatewithdll have to be in a dll.?

alex on 8/6/2008 11:46:42 AM (62 days ago)

This is what i am thinking of using now.

string playerToLeft = "";
int playerToLeftIndex = 0;
for( int i = 0; i < newGame.Players.Count; i++ ) {
if( newGame.Players[i].Name == currentPlayer ) {
break;
}
if( newGame.Players[i].IsInTheHand ) {
playerToLeftIndex = i;
playerToLeft = newGame.Players[i].Name;
}

}
if( playerToLeft.Length > 0 ) {

LastChance on 8/6/2008 3:36:52 PM (62 days ago)

@LastChance
Why bother trying to control which turn it is.. it will get problematic, when people are sitting out and when people are joining...etc. My method for determining whether or not its my own turn works great:

//looks to see if the button is blue
public void CheckForButtonAndMakeAction()
{
try
{
Win32.RECT myRect = new Win32.RECT();
Win32.GetWindowRect((IntPtr)WindowHandle, out myRect);

//always a button at space number 1
float button1XOffset = myRect.Width * 0.34f;
float button1YOffset = myRect.Height * 0.07f;
Point oldPoint = new Point(myRect.Right - (int)button1XOffset, myRect.Bottom - (int)button1YOffset);

Bitmap bmpScreenshot = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(oldPoint.X, oldPoint.Y, 0, 0, new Size(1, 1), CopyPixelOperation.SourceCopy);
Color myColor = bmpScreenshot.GetPixel(0, 0);
//Console.WriteLine(string.Format("R:{0} G:{1} B:{2}", myColor.R.ToString(), myColor.G.ToString(), myColor.B.ToString()));
if (myColor.B > myColor.R && myColor.B > myColor.G)
{
MakeDecision();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

H4mm3rHead on 8/8/2008 11:05:03 AM (60 days ago)

Are you just calling CheckForButtonAndMakeAction on a endlessloop then?
I will give it a try
are the offsets that you post for PS or FTP
If you have the ones for FTP I would apprecaite them.

Thanks

LastChance on 8/8/2008 9:35:12 PM (60 days ago)

Tried to hook the example to Poker Academy but all what I get is the text of the main window. The file monitors seem to work OK. Only DrawTextEx seems to produce output. Spy++ does not find any other windows in the PA UI than com.biotools.poker.PokerApp.

WTF, maybe that PA is a java app has something to do with this ??. Any ideas ??

tatsa on 8/10/2008 2:11:19 PM (58 days ago)

What are reasonable methods online poker rooms might use to detect these 'bots'?
- scanning process names
- scanning window names

For those of us new to Windows development, how do we do simple things like change these simple values to protect ourselves?

What about the 'fingerprint' of the executable?

Obfuscation on 8/10/2008 5:13:36 PM (58 days ago)

Obfuscation:

- Many of these poker clients inject global hooks to monitor the keyboard and mouse to see if they are controlled by a program.
- They might also go through your internet surf history to find out if you have been here Smile.
- Registry scanning for unwanted programs.
- Taking screen grabs to see what you are doing.

There is software to defend against hooking (ProcessGuard).Nevertheless by using it you reveal the fact that you don't want your computer to be snooped.

For all fellow botters:

- Don't underestimate the capability of the venue to snoop your computer.

tatsa on 8/11/2008 12:49:35 AM (58 days ago)

I know that a popular MMORPG client did indeed do some of these very things. It was seen going through window names and process lists and looking for specific signatures, but the mmorpg claimed they only hashed the window and process titles and unless they matched a very small list of things they were looking for, they couldn't know what you were doing.

There was suspicion that they did screen grabs bc one hack visually hid itself as an option, but there was never any confirmation. Running processguard may in the worst case get your account flagged by the mmo, but even as aggressive as they were, it never got you banned. False positives were terrible for PR.

I get the sense that online casinos have even less to lose because of mediocre bots and as the author points out, gains quite a bit. So I doubt they would engage in such aggressive measures and risk the bad PR. In fact, I'm confident screengrabs and collecting actual window titles would be grounds for legal action against whoever was doing the snooping. However, I'm sure a few of us checking with something like ProcessGuard would give be helpful.

Having said that, a bit of search and replace allowed me to change the window title. IF the claim that they are only hashing windows is true, then simply adding a random character would be enough to throw the hash. I went a step further and changed to to be something completely different. If they were actually taking screen grabs, there's little you can do about that.

As for the process and executable name, it was a little less obvious, but still worth kicking myself for. I just needed to right click on the project name in the explorer on the left and rename it. The source files can retain the names and I don't think it matters. Of course as I write this, I wonder if I could have simply changed the .exe name ><

Obfuscation on 8/11/2008 8:57:45 AM (57 days ago)

Oh and hooking the keyboard and mouse would be definitely grounds for legal action, assorted troubles because it exposes them to private info like cc numbers and passwords.

Obfuscation on 8/11/2008 8:58:43 AM (57 days ago)

Being less savvy with windows than I am with *nix, I can't confirm this on a more basic level than using the Windows Task Manager and looking at the process list (the equivalent on a mac or linux box is to look at top). With regard to changing the process name in this domain, simply renaming the file does seem to do the trick. E.g. renaming XPokerBot.MfcView.exe to calculator.exe will indeed display calculator.exe in the process list.

Questions:
- can the source directory for this process be detected? E.g. if my 'calculator.exe' resides in a directory called 'omgimabot', will they know that?

Obfuscation on 8/11/2008 11:06:47 AM (57 days ago)

Obfuscation: This is very obvious for most I'd think, but to make it absolutely clear:

Any software running on you computer, can potentially do anything with your computer.
So yes, "they" can snoop the directory, or even download your calculator.exe

As for any legal action; which country is the venues servers running? Maybe in a country where no such laws exist. But most probably you've already accepted this snooping when you clicked "I accept" on the terms of use/lisence agreement.

Nyx on 8/11/2008 11:29:34 AM (57 days ago)

Nyx:

Potentially, yes. But there's a fine line between what someone who fears no consequences (e.g. virus author) can do versus a company with a name like Pokerstars or Fulltilt who has to deal with the public.

If one of the clients is outright downloading window title strings and grabbing screens or browser history wholesale, they would face quite the backlash from the community. The closest thing they've gotten away with is comparing hashed results, which protects the end users' privacy, but allows the client program to check only for _specific_ things. This is why detecting known hacks and bots is trivial.

In the MMORPG I was referring to, successful hacks even to this day get away with it simply by adding a random string to their window title - thus screwing the hash. For those unfamiliar with this tactic, here's a summary. If, for example, they're looking for "XPokerBot", one approach which allows them to not invade privacy is to hash that string "XPokerBot" into a unique identifier like 'ABCDEFG' (to overly simplify things). Then, if they rifle through your window titles, they use the same technique of hashing all window titles, each generating an identifier. Here's an example:

- "How I Built a Working Online Poker Bot, Part 5: Deciphering Poker Stars and Full Tilt - Coding the Wheel" might be hashed into 'QWERTYY'
- "Windows Task Manager" might be hashed into 'LKJHGFD'
- if you were running a window with the title "XPokerBot", it would also generate the hash 'ABCDEFG'

These hashes are then used for comparison. The window with the hash 'ABCDEFG' would match and alert whoever needed to know. Of course, they would double check with other methods or flag your account for further scrutiny.

If you were able to rename your window title to "XPokerBot2", the hash would be completely different. It may work out to be 'ABCDEFH' or 'ZCZCZCZC', but the point is, it won't match and they can make no assumptions about it.

In reality, they would probably be checking for a number of possible hashes, but these mmo hacks which are still successful defeat this method of detection simply by adding a randomly generated string or completely replacing the window title with a randomly generated string or something you can specify yourself.

I hope that makes sense.

Obfuscation on 8/11/2008 12:22:37 PM (57 days ago)

It makes perfect sense.

But I doubt they simply hash the windowtitle, it's just as easy to hash dll's or other executables memory image. And if said piece of software resides within their softwares memoryspace, like the hook.dll, they are probably within the legal limits to do just that.

Why hash in the first place? I can think of 2 reasons
1. It saves bandwidth at the expense of clientside cpu cycles.
2. It's close to impossible to detect whats going on with a simple network analyzer/sniffer.

How to defeat it?
Randomization, as obfuscation points out, and encryption.
What I'm really curious about, what is it James has up his sleeve (pocket aces? Laughing )

Paranoia is healty Smile
Nyx

Nyx on 8/11/2008 3:04:43 PM (57 days ago)

Why hash in the first place? I can think of 2 reasons
1. It saves bandwidth at the expense of clientside cpu cycles.
2. It's close to impossible to detect whats going on with a simple network analyzer/sniffer.


It also gives them legal shelter should anyone scream invasion of privacy. Hashing means they won't know anything except whether or not a hash matched one of their known hashes. If they didn't hash, it would be a legal field day.

Paranoia is quite healthy indeed.

Obfuscation on 8/11/2008 3:42:02 PM (57 days ago)

Hello,
Can someone please help me with integrating this project with C#?
I made a C# project inside of the solution, and changed the s_TargetExeCaption field in ApplicationProxy.cpp of XPokerBot.Hook to the caption of my project, and gave my C# program WM_COPYDATA handling. But since I don't even know if it's possible to use detours in C#, I added system(path to my C# exe) after the code that injects the dll when the Launch button is pressed in XPokerBot.MfcView.
Now when I run MfcView it injects PokerStars then runs my C# exe, but when I try to read the data sent from a WM_COPYDATA message from it's pointer, I get an error that says "Attempt to access protected memory". I'm guessing that this is because my C# program is not related to my injected pokerstars.exe, and the C++ exe doesn't have this problem because it is the parent of the pokerstars.exe.

Has anyone encountered this problem / does anyone have any other ways to integrate C# with the dll?

Anonymous on 8/11/2008 5:01:25 PM (57 days ago)

Take a look at part 6, The sources there has all you need

Nyx on 8/11/2008 7:38:23 PM (57 days ago)

Oh my god I just wasted so much time on something that was so simple and one page away. Thanks Nyx, people like you keep me from going crazy overthinking everything. Smile

Anonymous on 8/12/2008 3:25:49 AM (56 days ago)

Hello again,
I have tried to combine the code from part 6 into this part, which left me with a button in my C# program installing the hook. I have limited the injected dll to only send the "new table opened" message by commenting out the other functions. And I now have this for my WM_COPYDATA receiving code:

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COPYDATA)
{
COPYDATASTRUCT cds = (COPYDATASTRUCT)
Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));

TABLE_SUMMARY ht = (TABLE_SUMMARY)Marshal.PtrToStructure(cds.lpData, typeof(TABLE_SUMMARY));

idBox.Text = ht.Window.ToString();
dataBox.Text = ht.TableName.ToString();
}
else
base.WndProc(ref m);
}


Here are the structs it refrences:
[quote]
const int WM_COPYDATA = 0x004A;

public struct COPYDATASTRUCT
{
public int dwData;
public int cbData;
public IntPtr lpData;
};

public struct TABLE_SUMMARY
{
public IntPtr Window;
public string TableName;
public string PlayerName;
public int LimitType;
public bool IsPlayMoney;
public bool IsTourney;
public double[] Limits;
public double[] Blinds;
public double Ante;
public int Venue;
public int SeatCount;
public int DisplayType;
}
[/QUOTE]

Before I implemented TABLE_SUMMARY into my program, my textboxes would show the pointer to the information fine. But now that I have TABLE_SUMMARY in, when it gets to that part of the code (I know that this happens at those lines since it only happens when I open a table and click on my app and back on the table), my program crashes. Even when I debug the program I get no information other than "APPCRASH".

Anonymouss on 8/12/2008 6:03:46 AM (56 days ago)

The problem is probably the double[] arrays, which has no defined size.

Nyx on 8/12/2008 9:45:48 AM (56 days ago)

You're right, when I comment them out the code runs. How exactly am i supposed to define their size? It won't allow me to use fixed or new double[2] in the struct

Anonymouss on 8/13/2008 3:57:58 AM (55 days ago)

I'm not certain exactly how, many options
I'm not to familliar with the interop, but something like this

[MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
Public double[] Limits

or if you know the array is only 2 doubles wide, do a workaround like this
public double Limits1;
public double Limits2;

or the bad way (which I like) dont bother with the struct, use unsafe and manipulate the pointer

Nyx on 8/13/2008 6:19:18 AM (55 days ago)

Thank you very much Nyx. I used the MarshalAs method and now my C# application has all of the functionality that MfcView does. All I need to do now is to incorporate some logic into it and give it to the ability to click.

Anonymouss on 8/13/2008 5:35:25 PM (55 days ago)

James, with the code outlined in the articles there are various means to monitor table state. Given the hand history you can rebuild the table state since the end of the previous hand. With the chat window information you can monitor the state of the hand as it occurs. But the one part of the modeling that I cannot seem to update is the player's chip count. If a player buys in for more chips between hands it is not updated anywhere but the poker table window. How do you go about monitoring this in regards to table state? Do you hook the calls that render the names and numbers within the table windows?

Andrew G. on 8/17/2008 11:26:54 PM (51 days ago)

>But the one part of the modeling that I cannot seem to update is the player's chip count.

Here are a few options:

- First, make sure that information isn't being emitted into a log file, or some other easy-to-access location.
- If the poker client uses typical text output APIs, you can hook them, and infer from the X,Y coordinates which seat is being written to.
- If the poker client uses bitmapped fonts or other bit-blitting to draw the stack sizes, think about what it takes to generate an image of a numeral such as "4" and display it on the screen (without using DrawText/TextOut/etc.). Typically, it means loading an image, a bitmap font, or calling a traditional text output API on an in-memory bitmap, and subsequently blitting from that to the display surface. So the tiny little images for the "0" and the "1" etc. have to come from somewhere, by tracing backwards you can ferret this out.
- Beneath the UI, rest assured there's a data structure containing the stack sizes, and rest assured there's a function which gets called when a player's stack size changes. We'll talk more about this down the road.
- In certain clients, a window message will be directed to the table window when a stack size changes...
- Not to mention using OCR. That can mean a full-fledged 3rd-party OCR, although honestly, hand-rolled OCR is feasible if all you have to recognize are 0-9 and the decimal point. You can use tricks in this case similar to the three-pixel Ace of Spades test I mentioned back in Part 1.

It really depends on the specific client you're dealing with.

James Devlin on 8/18/2008 8:04:46 AM (50 days ago)

Thanks for the response James. I guess I should have mentioned it my previous post, but the client I'm having trouble with is Stars. I figure that the numbers displayed in the windows are written with some text output API, but what other text APIs are there other then the ones outlined in the code, TextOut, ExtTextOut, DrawText, DrawTextEx?

I like the idea of querying the underlying data structures. How difficult is that to implement? Hopefully in another post..

Andrew G. on 8/18/2008 6:54:36 PM (50 days ago)

How do we prevent ourselves from being detected when applications like the one below can view our injected .DLL?

http://www.nirsoft.net/utils/injected_dll.html

Mark on 8/19/2008 9:39:16 PM (49 days ago)

I use to be loosely associated with a poker stat collecting software app (not here to advertise though). From extensive readings in that forum and others I can tell you that only a few poker-sites state adamantly that bots and stat collection software that use centralized databases are not allowed. Of those... only two (PS & PP) actually use their client app to check your system.

They don't disallow all DLL injections on your system... too many of those are required by the system or major apps or for good purposes. They check for specific known products by tell-tell signs of it on your system (registry, file system, IE history). Products that have sold thousands of copies.

They aren't worried about the little guy building a bot for free that could be under any name today and maybe a different name next week... that may or may not be able to get his bot working, and may or may not be able to break even with it when he does. They're only worried about the big bot software companies whose technology could be used in collusion rings, or centralized stat databases where paying members get tons of stat data on players they've never played against or even seen. I know a bit about this... but I'm still here enjoying this fun project.

DM on 8/22/2008 12:11:56 AM (47 days ago)

Is it possible to grab text from a Java app? I'm trying to get this to work with Poker Academy, but the only function calls I see are CreateFile and WriteFile, no TextOut/ExtTextOut. How does the JVM put text in the window?

M on 9/10/2008 11:32:26 AM (27 days ago)

First of all thanks for your posts James. I have actually stopped playing poker to learn the bot code!

I am learning by messing around and extending your code. I have got to the point of getting the hole cards from the log file. And also the hexidecimal number for the PokerTable window ID.

My problem is that I now have a string type like 00020AC7 and I need to obtain the HWND handle to the poker table window that it corresponds to.

My programming skills are rather basic. I know there must be a simple way of doing it, but the "fight club" of bot programming is kicking my ass...

Any help / example code from anyone would be much appreciated.

Thanks

SteveT on 9/12/2008 2:05:49 PM (25 days ago)

Comment on this post:

Thanks for your interest in Coding the Wheel. All fields are optional.