Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Playing Video Games One Frame at a Time

Playing Video Games One Frame at a Time

Video games are hard and as I age my reaction time has gone down. But I'm also a programmer and I can write tools that solve this for me. This talk will go over what it means to play video games with the assistance of tools and show a few examples of how this can be done using C++. From games that support creating tools to injecting your own code into a game. This is an introductory talk on this topic but it will cover a few lower level systems interactions. No video game knowledge is needed.

Ólafur Waage

November 19, 2023
Tweet

More Decks by Ólafur Waage

Other Decks in Programming

Transcript

  1. 1 TEST SLIDE Text is usually about this size and

    color It might go this far down. ^ code will be this color on this background and this example is roughly the smallest it will get. It will usually be bigger. If you can’t read it, move closer please.
  2. 4

  3. 5

  4. 6

  5. Worked on ATC systems for a couple of years. In

    the gaming industry for 7 years. As a consultant in Norway for a couple of years.
  6. Worked on ATC systems for a couple of years. In

    the gaming industry for 7 years. As a consultant in Norway for a couple of years.
  7. Worked on ATC systems for a couple of years. In

    the gaming industry for 7 years. As a consultant in Norway for a couple of years.
  8. What’s going on here? A good way to describe this

    talk is: - A bit of silly fun 15
  9. What’s going on here? A good way to describe this

    talk is: - A bit of silly fun - A bit of curiosity 16
  10. What’s going on here? A good way to describe this

    talk is: - A bit of silly fun - A bit of curiosity - A bit of real life use cases 17
  11. What’s going on here? A good way to describe this

    talk is: - A bit of silly fun - A bit of curiosity - A bit of real life use cases This is probably not an area a lot of people have thought about, so let’s explore together. 18
  12. Last year? Also… I did a talk last year, that

    was way more serious than this one. 21
  13. Last year? Also… I did a talk last year, that

    was way more serious than this one. (about how humans learn information) 22
  14. Last year? Also… I did a talk last year, that

    was way more serious than this one. (about how humans learn information) And in that talk I said this… 23
  15. "Unfortunately, in this case there is considerable evidence that in

    many situations this strategy (1 hour lectures)
  16. "Unfortunately, in this case there is considerable evidence that in

    many situations this strategy (1 hour lectures) is rather poor (Bligh, 1971).
  17. "Unfortunately, in this case there is considerable evidence that in

    many situations this strategy (1 hour lectures) is rather poor (Bligh, 1971). A lecture may inspire, motivate and inform, but rarely fulfils the principles for effective learning; it is certainly inadequate for developing high-level skills"
  18. Last year? So, I can’t in good conscience make a

    talk this year that tries to effectively teach you something. 28
  19. Last year? So, I can’t in good conscience make a

    talk this year that tries to effectively teach you something. Then instead I decided to make a fun talk that does have some real life applications that you might not have thought about. 29
  20. Before I start I will do stuff to video games

    in this talk. If you are going to do similar stuff, please, and I’m asking nicely, only do this to single player non-online games. 33
  21. Before I start I will do stuff to video games

    in this talk. If you are going to do similar stuff, please, and I’m asking nicely, only do this to single player non-online games. I’m not going to do crazy stuff here, but I feel the need to add this warning. 34
  22. Playing video games is great fun, but I’m also a

    programmer. How can I marry these two things together?
  23. Playing video games is great fun, but I’m also a

    programmer. How can I marry these two things together? Well, you can make games.
  24. Playing video games is great fun, but I’m also a

    programmer. How can I marry these two things together? Well, you can make games. But what if there was another way?
  25. Games are just applications, so what can we do to

    control those applications remotely?
  26. Games are just applications, so what can we do to

    control those applications remotely? What are the different challenges you will face when trying to interact with complex software like this?
  27. Games are just applications, so what can we do to

    control those applications remotely? What are the different challenges you will face when trying to interact with complex software like this? And can some of this apply to interacting with other software?
  28. Level 1 What if the game you want to play

    supports playing it programmatically, right out of the box?
  29. 45

  30. Doom is a 1993 first person shooter. And it kind

    of redefined a few aspects of video games.
  31. Doom is a 1993 first person shooter. And it kind

    of redefined a few aspects of video games. - The look and feel of first person shooters
  32. Doom is a 1993 first person shooter. And it kind

    of redefined a few aspects of video games. - The look and feel of first person shooters - Online multiplayer
  33. Doom is a 1993 first person shooter. And it kind

    of redefined a few aspects of video games. - The look and feel of first person shooters - Online multiplayer - Game modification
  34. Doom is a 1993 first person shooter. And it kind

    of redefined a few aspects of video games. - The look and feel of first person shooters - Online multiplayer - Game modification - Video Game Speedrunning
  35. Doom is a 1993 first person shooter. And it kind

    of redefined a few aspects of video games. - The look and feel of first person shooters - Online multiplayer - Game modification - Video Game Speedrunning I can’t go over everything but let’s look at the last one.
  36. Whenever there is a timer, people will try to be

    the best, be the fastest. Doom is no exception.
  37. Whenever there is a timer, people will try to be

    the best, be the fastest. Doom is no exception. Because at the end of every stage, there was a timer.
  38. Whenever there is a timer, people will try to be

    the best, be the fastest. Doom is no exception. Because at the end of every stage, there was a timer. And as you can see, people are still playing, still trying to get better.
  39. And if you download these files, you’ll notice that they’re

    actually pretty small. The reason is that these files basically only contain what inputs the user pressed and during what frame.
  40. This is possible because of one thing. Doom is deterministic

    Doom is a single threaded application where every single entity in the map patiently waits their turn, always in the same order.
  41. This is possible because of one thing. Doom is deterministic

    Doom is a single threaded application where every single entity in the map patiently waits their turn, always in the same order.
  42. This is possible because of one thing. Doom is deterministic

    Doom is a single threaded application where every single entity in the map patiently waits their turn, always in the same order. And when they want to do something random, they extract a number from this table
  43. This is possible because of one thing. Doom is deterministic

    Doom is a single threaded application where every single entity in the map patiently waits their turn, always in the same order. And when they want to do something random, they extract a number from this table Then an index is incremented and the next entity will get the next number.
  44. So what if you wanted to take Doom and convert

    it to C++ (or some language)
  45. So what if you wanted to take Doom and convert

    it to C++ (or some language) How can you move forwards with that project knowing that your code changes and refactorings haven’t broken the game?
  46. So what if you wanted to take Doom and convert

    it to C++ (or some language) How can you move forwards with that project knowing that your code changes and refactorings haven’t broken the game? We could try playing the game, or writing unit tests.
  47. So what if you wanted to take Doom and convert

    it to C++ (or some language) How can you move forwards with that project knowing that your code changes and refactorings haven’t broken the game? We could try playing the game, or writing unit tests. But we have the tool in our hands right now.
  48. Approval testing is a methodology where you focus on comparing

    the output of the old known bit of code with the output of your new code.
  49. Approval testing is a methodology where you focus on comparing

    the output of the old known bit of code with the output of your new code. Think of it like a git diff. If there is a difference, then something broke.
  50. Approval testing is a methodology where you focus on comparing

    the output of the old known bit of code with the output of your new code. Think of it like a git diff. If there is a difference, then something broke. This is useful when you want to do a complete rewrite or when the original source might not be available in full.
  51. Doom can run the old demo files and then give

    you a nice statistics screen at the end.
  52. Doom can run the old demo files and then give

    you a nice statistics screen at the end. How long you played for, how many monsters you killed, how many items you got and how many secrets you found.
  53. Doom can run the old demo files and then give

    you a nice statistics screen at the end. How long you played for, how many monsters you killed, how many items you got and how many secrets you found. Well, if I play this demo on the new version, I should get the exact same results.
  54. Another tidbit. The game doesn’t need to render the game

    to the screen for the simulation to run.
  55. Another tidbit. The game doesn’t need to render the game

    to the screen for the simulation to run. The graphics are just a nice visual representation of the game state.
  56. Another tidbit. The game doesn’t need to render the game

    to the screen for the simulation to run. The graphics are just a nice visual representation of the game state. So we can add (and modify) some game flags where the game can run in the terminal.
  57. Another tidbit. The game doesn’t need to render the game

    to the screen for the simulation to run. The graphics are just a nice visual representation of the game state. So we can add (and modify) some game flags where the game can run in the terminal. This also means we don’t need to run the game at a nice frame rate, we can just run it as fast as possible.
  58. Another tidbit. The game doesn’t need to render the game

    to the screen for the simulation to run. The graphics are just a nice visual representation of the game state. So we can add (and modify) some game flags where the game can run in the terminal. This also means we don’t need to run the game at a nice frame rate, we can just run it as fast as possible. The simulation is the same.
  59. Putting 1 and 1 together. We can play the game

    using a known good version of the game.
  60. Putting 1 and 1 together. We can play the game

    using a known good version of the game. Collect the resulting Stats output.
  61. Putting 1 and 1 together. We can play the game

    using a known good version of the game. Collect the resulting Stats output. Save the demo files and the stats text files in a folder.
  62. Putting 1 and 1 together. We can play the game

    using a known good version of the game. Collect the resulting Stats output. Save the demo files and the stats text files in a folder. Run the game, in command line using those demos and check if the resulting stats data match the corresponding text file.
  63. Level 2 What if the game you want to play

    doesn't have the support Doom does?
  64. 96

  65. Bejeweled 3 is a match three game. Pick a gem,

    move it left/right or up/down to create three of a kind.
  66. Bejeweled 3 is a match three game. Pick a gem,

    move it left/right or up/down to create three of a kind. You can also join four or more gems for bonus points.
  67. Bejeweled 3 is a match three game. Pick a gem,

    move it left/right or up/down to create three of a kind. You can also join four or more gems for bonus points. After a match has been made, those gems go away and new ones drop down.
  68. For Bejeweled 3 the plan of action is pretty simple

    - What Gem is where - Pick a good move
  69. For Bejeweled 3 the plan of action is pretty simple

    - What Gem is where - Pick a good move - Move that gem
  70. For Bejeweled 3 the plan of action is pretty simple

    - What Gem is where - Pick a good move - Move that gem - Repeat
  71. 64px Step 1 What Gem is Where? The game board

    is fixed resolution, which means each cell is 64 by 64 pixels.
  72. w: 261px h: 37px Step 1 What Gem is Where?

    The game board is fixed resolution, which means each cell is 64 by 64 pixels. That means that the board starts at 261x37 from the top left of the game screen.
  73. Step 1 What Gem is Where? The game board is

    fixed resolution, which means each cell is 64 by 64 pixels. That means that the board starts at 261x37 from the top left of the game screen. From that information, I know exactly where each cell on the board is.
  74. Step 1 What Gem is Where? But how do I

    know that this gem is the green one?
  75. Step 1 What Gem is Where? But how do I

    know that this gem is the green one? I started simple, let’s take the center pixel of that gem and check the RGB color values.
  76. Step 1 What Gem is Where? But how do I

    know that this gem is the green one? I started simple, let’s take the center pixel of that gem and check the RGB color values. But there’s a problem.
  77. Step 1 What Gem is Where? But how do I

    know that this gem is the green one? I started simple, let’s take the center pixel of that gem and check the RGB color values. But there’s a problem.
  78. Step 1 What Gem is Where? Let’s use OpenCV to

    our advantage. Using Template Matching we can look for our gems on the board.
  79. Step 1 What Gem is Where? Let’s use OpenCV to

    our advantage. Using Template Matching we can look for our gems on the board. I created these nice sample images of each gem.
  80. Step 1 What Gem is Where? Let’s use OpenCV to

    our advantage. Using Template Matching we can look for our gems on the board. I created these nice sample images of each gem. So why doesn’t this work?
  81. Step 1 What Gem is Where? Let’s use OpenCV to

    our advantage. Using Template Matching we can look for our gems on the board. I created these nice sample images of each gem. So why doesn’t this work? Many feature detection algorithms’ first step is to make the source image B&W
  82. Step 1 What Gem is Where? Let’s go back to

    the idea of color. What if I don’t check for 1 pixel in the center, but the general … hue … of the center area.
  83. Step 1 What Gem is Where? Let’s go back to

    the idea of color. What if I don’t check for 1 pixel in the center, but the general … hue … of the center area. So I grab a 32x32 area in the center of the gem.
  84. Step 1 What Gem is Where? Let’s go back to

    the idea of color. What if I don’t check for 1 pixel in the center, but the general … hue … of the center area. So I grab a 32x32 area in the center of the gem. And ask OpenCV what the average color of that area.
  85. Step 1 What Gem is Where? Let’s go back to

    the idea of color. What if I don’t check for 1 pixel in the center, but the general … hue … of the center area. So I grab a 32x32 area in the center of the gem. And ask OpenCV what the average color of that area. And check against HSV and not RGB
  86. Step 1 What Gem is Where? Let’s go back to

    the idea of color. What if I don’t check for 1 pixel in the center, but the general … hue … of the center area. So I grab a 32x32 area in the center of the gem. And ask OpenCV what the average color of that area. And check against HSV and not RGB
  87. Step 1 What Gem is Where? So I went through

    and checked the Hue value of every single gem (when stationary and while spinning).
  88. Step 1 What Gem is Where? So I went through

    and checked the Hue value of every single gem (when stationary and while spinning). And made a chart of where they overlap and where they are isolated.
  89. Step 1 What Gem is Where? So I went through

    and checked the Hue value of every single gem (when stationary and while spinning). And made a chart of where they overlap and where they are isolated.
  90. Step 1 What Gem is Where? So I went through

    and checked the Hue value of every single gem (when stationary and while spinning). And made a chart of where they overlap and where they are isolated. And then wrote a function that tries to disambiguate between the colors (and I used RGB to help also)
  91. Step 1 What Gem is Where? So I went through

    and checked the Hue value of every single gem (when stationary and while spinning). And made a chart of where they overlap and where they are isolated. And then wrote a function that tries to disambiguate between the colors (and I used RGB to help also)
  92. Step 1 What Gem is Where? So I went through

    and checked the Hue value of every single gem (when stationary and while spinning). And made a chart of where they overlap and where they are isolated. And then wrote a function that tries to disambiguate between the colors (and I used RGB to help also)
  93. Step 1 What Gem is Where? So I went through

    and checked the Hue value of every single gem (when stationary and while spinning). And made a chart of where they overlap and where they are isolated. And then wrote a function that tries to disambiguate between the colors (and I used RGB to help also)
  94. Step 1 What Gem is Where? So I went through

    and checked the Hue value of every single gem (when stationary and while spinning). And made a chart of where they overlap and where they are isolated. And then wrote a function that tries to disambiguate between the colors (and I used RGB to help also)
  95. Step 2 Pick a good move. So what is a

    good move? Initially I was thinking of writing some cool algorithm, get some deep learning AI into the mix.
  96. Step 2 Pick a good move. So what is a

    good move? Initially I was thinking of writing some cool algorithm, get some deep learning AI into the mix. But after the color fiasko, I wanted to see if something simple was enough.
  97. Step 2 Pick a good move. So what is a

    good move? Initially I was thinking of writing some cool algorithm, get some deep learning AI into the mix. But after the color fiasko, I wanted to see if something simple was enough. And it was.
  98. Step 2 Pick a good move. Let’s start by playing

    the game a bit and see if anything pops out.
  99. Step 2 Pick a good move. Let’s start by playing

    the game a bit and see if anything pops out. So I played the game a little bit. Just a bit.
  100. Step 2 Pick a good move. Let’s start by playing

    the game a bit and see if anything pops out. So I played the game a little bit. Just a bit. And I had an idea.
  101. Step 2 Pick a good move. Let’s start by playing

    the game a bit and see if anything pops out. So I played the game a little bit. Just a bit. And I had an idea. There aren’t actually that many moves in this game.
  102. Step 2 Pick a good move. Let’s start by playing

    the game a bit and see if anything pops out. So I played the game a little bit. Just a bit. And I had an idea. There aren’t actually that many moves in this game. Can we just map them out?
  103. 151

  104. 152

  105. 153

  106. 154

  107. 155

  108. 156

  109. 157

  110. 158

  111. 159

  112. 160

  113. Step 2 Pick a good move. But which move should

    we pick? Well a high value move is always sorted above other moves. But what if all moves have the same value?
  114. Step 2 Pick a good move. But which move should

    we pick? Well a high value move is always sorted above other moves. But what if all moves have the same value? Then we pick a move that is lower on the board. Why?
  115. Step 2 Pick a good move. But which move should

    we pick? Well a high value move is always sorted above other moves. But what if all moves have the same value? Then we pick a move that is lower on the board. Why? Because it creates more matching opportunities when tiles fall down. A move at the top only creates one.
  116. Step 3 Move that gem. Now it’s time to interact

    with the game application directly.
  117. Step 3 Move that gem. Now it’s time to interact

    with the game application directly. The Windows SDK has a lot of nice mouse input functions. So let’s use them.
  118. Step 3 Move that gem. Now it’s time to interact

    with the game application directly. The Windows SDK has a lot of nice mouse input functions. So let’s use them. I basically want a function like this. I know where the gem is and I know what direction I want to move to.
  119. 182

  120. 183

  121. VVVVVV Does not have built in support for giving the

    game the inputs. Does not have a simple game state.
  122. VVVVVV Does not have built in support for giving the

    game the inputs. Does not have a simple game state. Is fast paced and you need to be pretty accurate with your movement.
  123. 187

  124. 188

  125. Before I continue with the madness. There is one concept

    I need to talk about. The Game Loop
  126. Before I continue with the madness. There is one concept

    I need to talk about. The Game Loop Games are applications like any other, and they usually follow a certain set of steps.
  127. Before I continue with the madness. There is one concept

    I need to talk about. The Game Loop Games are applications like any other, and they usually follow a certain set of steps. - Get input from user
  128. Before I continue with the madness. There is one concept

    I need to talk about. The Game Loop Games are applications like any other, and they usually follow a certain set of steps. - Get input from user - Update the state
  129. Before I continue with the madness. There is one concept

    I need to talk about. The Game Loop Games are applications like any other, and they usually follow a certain set of steps. - Get input from user - Update the state - Draw the current state
  130. There are a few caveats with these steps that makes

    our work harder. Get input from user There might be no input or if we handle it badly, we might delay it or miss it.
  131. There are a few caveats with these steps that makes

    our work harder. Get input from user There might be no input or if we handle it badly, we might delay it or miss it. Update the state This can take a long time and we might multi-thread it.
  132. There are a few caveats with these steps that makes

    our work harder. Get input from user There might be no input or if we handle it badly, we might delay it or miss it. Update the state This can take a long time and we might multi-thread it. Draw the current state We might draw old state or we might offload the draw to happen in another thread.
  133. 211 Initialize Process input Update game state Draw game state

    *As often as we can At least once per 16.666 ms
  134. 212

  135. 213

  136. 214

  137. 215

  138. 216

  139. 217

  140. 218

  141. 219

  142. 220

  143. 221

  144. 222

  145. 223

  146. VVVVVV actually has a few advantages and is why I

    picked this game for the project.
  147. VVVVVV actually has a few advantages and is why I

    picked this game for the project. It’s open source, so we can just go check.
  148. VVVVVV actually has a few advantages and is why I

    picked this game for the project. It’s open source, so we can just go check. It’s single threaded.
  149. VVVVVV actually has a few advantages and is why I

    picked this game for the project. It’s open source, so we can just go check. It’s single threaded. It has a lot of customization for such a simple game.
  150. So here is my plan Launch the game as a

    paused child process of some loader. Loader
  151. So here is my plan Launch the game as a

    paused child process of some loader. Loader Game Process
  152. So here is my plan Launch the game as a

    paused child process of some loader. Loader Game Process dll
  153. So here is my plan Launch the game as a

    paused child process of some loader. Hook the function that creates the DirectX Device. Loader Game Process dll
  154. So here is my plan Launch the game as a

    paused child process of some loader. Hook the function that creates the DirectX Device. Get the address of that device. Loader Game Process dll
  155. So here is my plan Launch the game as a

    paused child process of some loader. Hook the function that creates the DirectX Device. Get the address of that device. Intercept the game’s draw call and call our draw function first. Loader Game Process dll
  156. So here is my plan Launch the game as a

    paused child process of some loader. Hook the function that creates the DirectX Device. Get the address of that device. Intercept the game’s draw call and call our draw function first. Before each frame, send our keyboard inputs. Loader Game Process dll
  157. 238 Initialize Process input Update game state Draw game state

    Intercept - Call game’s draw function - Send our inputs
  158. 239 Initialize Process input Update game state Draw game state

    We could hook the input polling function.
  159. 240 Initialize Process input Update game state Draw game state

    We could hook the input polling function. But we actually want to do a bit of drawing ourselves, to make a nice debug UI.
  160. 241

  161. 242

  162. 243

  163. 244

  164. 245

  165. 246

  166. 247

  167. 248

  168. 249

  169. 250

  170. 251

  171. 252

  172. 253

  173. 254

  174. 255

  175. 256

  176. 257

  177. 258

  178. 259

  179. 260

  180. 261

  181. 262

  182. 263

  183. 264

  184. 265

  185. 266

  186. 267

  187. 268

  188. 269

  189. 270

  190. 271

  191. A summary of what we’ve done so far. ✅ Spawn

    the game process paused. Loader Game Process dll
  192. A summary of what we’ve done so far. ✅ Spawn

    the game process paused. ✅ Attach our DLL to the game process. Loader Game Process dll
  193. A summary of what we’ve done so far. ✅ Spawn

    the game process paused. ✅ Attach our DLL to the game process. ✅ Hook the “CreateDevice” function the game is going to call once it starts. Loader Game Process dll
  194. A summary of what we’ve done so far. ✅ Spawn

    the game process paused. ✅ Attach our DLL to the game process. ✅ Hook the “CreateDevice” function the game is going to call once it starts. Once the game calls the “CreateDevice” function, get the device it just made and hook end “EndScene” function. Loader Game Process dll
  195. 277

  196. 278

  197. 279

  198. 280

  199. 281

  200. 282

  201. 283

  202. 284

  203. 285

  204. 286

  205. 287

  206. 288

  207. 289

  208. 290

  209. Summary: Games are neat and it’s fun to play with

    them programmatically. Loader Game Process dll
  210. Summary: Games are neat and it’s fun to play with

    them programmatically. When you have an application you don’t have the source code to, there are still ways to automatically interact with it. Loader Game Process dll
  211. Summary: Games are neat and it’s fun to play with

    them programmatically. When you have an application you don’t have the source code to, there are still ways to automatically interact with it. AKA. Yes, you can still test that old legacy app. Yes you can still do safe(er) refactoring. Loader Game Process dll
  212. Summary: Games are neat and it’s fun to play with

    them programmatically. When you have an application you don’t have the source code to, there are still ways to automatically interact with it. AKA. Yes, you can still test that old legacy app. Yes you can still do safe(er) refactoring. Write more tests! Loader Game Process dll