{"id":2026,"date":"2021-09-20T07:25:09","date_gmt":"2021-09-20T12:25:09","guid":{"rendered":"https:\/\/badecho.com\/?p=2026"},"modified":"2021-09-22T07:42:30","modified_gmt":"2021-09-22T12:42:30","slug":"hacking-nioh-part-2","status":"publish","type":"post","link":"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/","title":{"rendered":"Hacking Nioh 2 &#8211; Part 2 (Apocalypse)"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"273\" height=\"364\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2.jpg\" alt=\"Nioh 2\" class=\"wp-image-1993\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2.jpg 273w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2-225x300.jpg 225w\" sizes=\"(max-width: 273px) 100vw, 273px\" \/><\/figure><\/div>\n\n\n\n<p>Onwards with the implementation of the <a href=\"https:\/\/badecho.com\/index.php\/2020\/10\/19\/apocalypse-system\/\" target=\"_blank\" rel=\"noreferrer noopener\">Apocalypse system<\/a> into the game <em>Nioh 2<\/em>. It is the first of the game-neutral <a href=\"https:\/\/badecho.com\/index.php\/what-is-omnified\/\" target=\"_blank\" rel=\"noreferrer noopener\">Omnified<\/a> systems I tend to implement, and it completely changes the consequences of letting yourself get hit by enemies, raising the stakes to ridiculous degrees.<\/p>\n\n\n\n<p>It also tends to be the easiest of my systems to implement, although this will, of course, vary from game to game. Each and every implementation is a learning experience, from which we&#8217;re (hopefully) better off from how we were before. <\/p>\n\n\n\n<p>While one can watch the times I hack on stream and maybe learn something from that, you don&#8217;t always know what&#8217;s going on in my head, and it is a lot to take in; that&#8217;s why I write these articles. I&#8217;m still learning how to trim unnecessary information from these writeups, but there&#8217;s just so much to cover always.<\/p>\n\n\n\n<p>Today, we&#8217;ll go over how we found the ideal place to insert the Apocalypse system into <em>Nioh 2<\/em>, as well as some other challenges we had to face and correct. We&#8217;ll be starting off, however, with an examination of how fall damage works in the game.<\/p>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_11 counter-hierarchy counter-decimal ez-toc-grey\">\r\n<div class=\"ez-toc-title-container\">\r\n<p class=\"ez-toc-title\">Table of Contents<\/p>\r\n<span class=\"ez-toc-title-toggle\"><a class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\"><i class=\"ez-toc-glyphicon ez-toc-icon-toggle\"><\/i><\/a><\/span><\/div>\r\n<nav><ul class=\"ez-toc-list ez-toc-list-level-1\"><li class=\"ez-toc-page-1 ez-toc-heading-level-2\"><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#I%E2%80%99ve_Fallen_and_It_Doesn%E2%80%99t_Hurt\" title=\"I\u2019ve Fallen and It Doesn\u2019t Hurt\">I\u2019ve Fallen and It Doesn\u2019t Hurt<\/a><ul class=\"ez-toc-list-level-3\"><li class=\"ez-toc-heading-level-3\"><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#The_Search_for_the_Last_Known_Location\" title=\"The Search for the Last Known Location\">The Search for the Last Known Location<\/a><\/li><li class=\"ez-toc-page-1 ez-toc-heading-level-3\"><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#Player_Last_Location_Hook\" title=\"Player Last Location Hook\">Player Last Location Hook<\/a><\/li><\/ul><\/li><li class=\"ez-toc-page-1 ez-toc-heading-level-2\"><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#Finding_the_Damage_Application_Code\" title=\"Finding the Damage Application Code\">Finding the Damage Application Code<\/a><\/li><li class=\"ez-toc-page-1 ez-toc-heading-level-2\"><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#No_Teleportitis_for_You!\" title=\"No Teleportitis for You!\">No Teleportitis for You!<\/a><ul class=\"ez-toc-list-level-3\"><li class=\"ez-toc-heading-level-3\"><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#Player_Location_Update_Frame_Skip_Hook\" title=\"Player Location Update Frame Skip Hook\">Player Location Update Frame Skip Hook<\/a><\/li><\/ul><\/li><li class=\"ez-toc-page-1 ez-toc-heading-level-2\"><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#Detecting_Player_As_the_Damage_Source\" title=\"Detecting Player As the Damage Source\">Detecting Player As the Damage Source<\/a><ul class=\"ez-toc-list-level-3\"><li class=\"ez-toc-heading-level-3\"><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#Player_Hit_Detection_Hook\" title=\"Player Hit Detection Hook\">Player Hit Detection Hook<\/a><\/li><\/ul><\/li><li class=\"ez-toc-page-1 ez-toc-heading-level-2\"><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#Apocalypse_Initiation_Hook\" title=\"Apocalypse Initiation Hook\">Apocalypse Initiation Hook<\/a><\/li><li class=\"ez-toc-page-1 ez-toc-heading-level-2\"><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#More_Omnification_To_Come\" title=\"More Omnification To Come\">More Omnification To Come<\/a><\/li><\/ul><\/nav><\/div>\r\n<h2><span class=\"ez-toc-section\" id=\"I%E2%80%99ve_Fallen_and_It_Doesn%E2%80%99t_Hurt\"><\/span>I\u2019ve Fallen and It Doesn\u2019t Hurt<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>As soon as I hacked the player&#8217;s location coordinates in the <a href=\"https:\/\/badecho.com\/index.php\/2021\/09\/17\/hacking-nioh-part-1\/\" target=\"_blank\" rel=\"noreferrer noopener\">previous article<\/a>, I observed what I knew would end up being a big problem once the Apocalypse system was implemented. If I changed my player&#8217;s y-coordinate (which is the vertical axis in this game) to a ridiculously high value, I would observe my player falling down from orbit, smashing into the ground, and sustaining no damage.<\/p>\n\n\n\n<p>Uh oh. A big part of what the Apocalypse system does is inflict the <em>teleportitis<\/em> effect on the character. This is a random displacement of the character to new coordinates, a &#8220;teleport&#8221; if you will. If the player is unlucky enough to have their vertical axis increased across a particular threshold, then music and fanfare plays as the player falls to the ground and dies horrifically.<\/p>\n\n\n\n<p>Well, there is no cause for music and fanfare if there is no death, so we had to fix that. Immediately, I suspected that the reason there was no damage was due to how the game calculated fall damage. Simply falling down and hitting the ground was not enough, rather a reference coordinate would be needed in order for the game to determine how far the player has fallen.<\/p>\n\n\n\n<p>This would be similar then to how the fall damage worked in <em>The Witcher 3<\/em>, as I eventually discovered when Omnifying that game. Of course, as far as Nioh 2 went, this was just a complete theory at this point in time by myself. Just a very educated guess. Regardless, we must trust our own experience, so I went ahead with attempting to locate a <em>last known location<\/em> coordinate triplet for the player, live on <a href=\"https:\/\/twitch.tv\/omni\" target=\"_blank\" rel=\"noreferrer noopener\">stream<\/a> of course.<\/p>\n\n\n\n<h3><span class=\"ez-toc-section\" id=\"The_Search_for_the_Last_Known_Location\"><\/span>The Search for the Last Known Location<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>I suspected that there would be a coordinate value in memory, similar to our source-of-truth y-coordinate value. If I could find this last location y-coordinate value and update it to the boosted value the y-coordinate was being set to following a teleportitis, it should then result in the player sustaining fatal damage upon hitting the ground.<\/p>\n\n\n\n<p>Right now, because the last location y-coordinate was remaining unchanged, the game would end up using a last location value equal to the ground position at the time of the player hits the ground when calculating the fall distance. It was my guess that the game would take the last known location, subtract the player&#8217;s source-of-truth y-coordinate from it upon smacking into the ground, and then use that difference as the fall distance.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"663\" height=\"600\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/fallDamage.png\" alt=\"Shows the relation between the last y-coordinate, y-coordinate, and fall damage.\" class=\"wp-image-2029\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/fallDamage.png 663w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/fallDamage-300x271.png 300w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/fallDamage-480x434.png 480w\" sizes=\"(max-width: 663px) 100vw, 663px\" \/><figcaption>We need to set the last known (before falling) y-coordinate in addition to sending the player up into the air if we want them to take damage.<\/figcaption><\/figure><\/div>\n\n\n\n<p>So, to find the last location y-coordinate value, I first looked for values close to the character&#8217;s y-coordinate value while we were on the ground. Following this, I set the player&#8217;s y-coordinate value to a very high height, while having a breakpoint at the character&#8217;s location update code. <\/p>\n\n\n\n<p>After allowing a few movement frames to pass, I looked among the previously searched for values for ones that remained unchanged. This took a few tries, with the first few attempts failing due to not observing the fact that the last known location would typically be underneath the source-of-truth y-coordinate value, as the player will tend to exist above the ground itself (it would tend to vary, however).<\/p>\n\n\n\n<p>Eventually, after widening the search enough, we got some useful search results.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"832\" height=\"806\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2WhereYouWereSearchResults.png\" alt=\"Shows the results of searching for the coordinates that track the last solid ground the player has stood on.\" class=\"wp-image-2002\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2WhereYouWereSearchResults.png 832w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2WhereYouWereSearchResults-300x291.png 300w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2WhereYouWereSearchResults-768x744.png 768w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2WhereYouWereSearchResults-480x465.png 480w\" sizes=\"(max-width: 832px) 100vw, 832px\" \/><figcaption>Here are the results of our search for the &#8220;last stable ground&#8221; coordinates for the player &#8212; or, as I also termed them: the &#8220;where we were&#8221; coordinates.<\/figcaption><\/figure><\/div>\n\n\n\n<p>After finding the last location y-coordinate value, I observed that setting both the last location and source-of-truth y-coordinate values to a fatal height would result in the player falling down a great height and <em>dying<\/em> horrifically. Score.<\/p>\n\n\n\n<p>Once found, I didn&#8217;t want to lose this precious bit of data ever again, so I set out to find a good place to hook into where we could reliably retrieve this data. It was important that the last location be available <em>prior<\/em> to any falling event, as we would need to be able to set it at any point in time while playing.<\/p>\n\n\n\n<h3><span class=\"ez-toc-section\" id=\"Player_Last_Location_Hook\"><\/span>Player Last Location Hook<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/ Gets the player's last location structure and ensures Omnified changes \n\/\/ to the player's vertical position is properly reflected.\n\/\/ [rsp+120] | {rsp+132}: Points to root structure of NPC the coordinates belong to.\n\/\/ [rdi+C8]: Player's last known y-coordinate on solid ground.\n\/\/ UNIQUE AOB: 89 87 C8 00 00 00 8B 47\n\/\/ Correct instruction will be single result found in nioh2.exe (not nvd3dumx.dll).\ndefine(omniPlayerLastLocationHook,&quot;nioh2.exe&quot;+8549BB)\n\nassert(omniPlayerLastLocationHook,89 87 C8 00 00 00)\nalloc(getPlayerLastLocation,$1000,omniPlayerLastLocationHook)\nalloc(playerLastLocation,8)\n\nregistersymbol(playerLastLocation)\nregistersymbol(omniPlayerLastLocationHook)\n\ngetPlayerLastLocation:\n    pushf\n    \/\/ The player location structure must be initialized in order for us to identify the player's\n    \/\/ last location structure.\n    push rax\n    mov rax,playerLocation\n    cmp [rax],0\n    pop rax\n    je getPlayerLastLocationOriginalCode\n    push rbx\n    push rcx\n    mov rbx,playerLocation\n    mov rcx,[rbx]    \n    \/\/ The player's location structure can be found here on the stack.\n    cmp rcx,[rsp+132]\n    jne getPlayerLastLocationCleanup\n    mov [playerLastLocation],rdi    \ngetPlayerLastLocationCleanup:\n    pop rcx\n    pop rbx\ngetPlayerLastLocationOriginalCode:\n    popf\n    mov [rdi+000000C8],eax\n    jmp getPlayerLastLocationReturn\n\nomniPlayerLastLocationHook:\n    jmp getPlayerLastLocation\n    nop \ngetPlayerLastLocationReturn:\n<\/pre>\n\n\n<p>A perfect hook for our purposes. As you can tell, more than just the player&#8217;s last location is being polled by the code here; rather, I suspect it was polling all the loaded NPCs as well. I managed to figure out we could filter out the player from the non-players by looking at the stack, on which the source-of-truth location structure for the creature being polled could be found.<\/p>\n\n\n\n<h2><span class=\"ez-toc-section\" id=\"Finding_the_Damage_Application_Code\"><\/span>Finding the Damage Application Code<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>In order to implement the Apocalypse system effectively, we need to hook it into the game&#8217;s <em>damage application<\/em> code. For more information on what that is exactly, you can always check the <a href=\"https:\/\/badecho.com\/index.php\/2020\/10\/19\/apocalypse-system\/#player-apocalypse-initiation-point\" target=\"_blank\" rel=\"noreferrer noopener\">relevant section in the Apocalypse system&#8217;s design article<\/a>.<\/p>\n\n\n\n<p>In summary, the damage application code is where the arithmetic is being performed to calculate a new health value in light of some damage that needs to be applied to it. It often can be quite far away from the more easily found <em>health update<\/em> code, which is simply the code that writes new health values to a particular source-of-truth health address.<\/p>\n\n\n\n<p>To find it, we&#8217;ll need to do a trace, several calls upon the stack from the health update code, which means we need to find that particular bit of code. We look for code writing to our already discovered health address, and find the following code to be writing to it after we get damaged by an enemy:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"1024\" height=\"576\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2HealthUpdateLocation-1024x576.png\" alt=\"Shows the health update code.\" class=\"wp-image-2006\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2HealthUpdateLocation-1024x576.png 1024w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2HealthUpdateLocation-300x169.png 300w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2HealthUpdateLocation-768x432.png 768w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2HealthUpdateLocation-480x270.png 480w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2HealthUpdateLocation.png 1132w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Here&#8217;s our health update code, now to find the damage application code that calculates the value found in rdx.<\/figcaption><\/figure><\/div>\n\n\n\n<p>You can see the call stack in the lower right of the image. We want to go as high as we can go (within reason) while still being able to maintain a single parent call to health update call ratio. If we go too high, we&#8217;ll run into methods that are continuously polling health values to update, and we won&#8217;t be able to capture the information related to a particular damage-derived change.<\/p>\n\n\n\n<p>Going three functions calls up the stack leads us to this code:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"1024\" height=\"637\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTraceStart-1024x637.png\" alt=\"Shows the code where we started our trace for the damage application code.\" class=\"wp-image-2004\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTraceStart-1024x637.png 1024w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTraceStart-300x187.png 300w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTraceStart-768x478.png 768w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTraceStart-480x299.png 480w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTraceStart.png 1183w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Here&#8217;s the parent function to the health update code we&#8217;ll be starting our trace from.<\/figcaption><\/figure><\/div>\n\n\n\n<p>It seems to be going off once per health update call. Hopefully it is high enough for our purposes! We perform a trace here, locate our health update code within the trace by searching for the proper instruction pointer address (held in <code>rip<\/code>), and then scroll up until we come to the following:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"1024\" height=\"568\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTrace-1024x568.png\" alt=\"Shows the results of the trace for the damage application code.\" class=\"wp-image-2005\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTrace-1024x568.png 1024w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTrace-300x166.png 300w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTrace-768x426.png 768w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTrace-480x266.png 480w, https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2DamageApplicationTrace.png 1093w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Here&#8217;s the results of the trace, along with (what appears to be) the damage application code highlighted.<\/figcaption><\/figure><\/div>\n\n\n\n<p>This is the damage application code. The damage amount can be found in the <code>edi<\/code> register, and it is being subtracted from the working value for the health, stored in <code>eax<\/code>. We can determine the target entity by looking at <code>ebx<\/code>. If it is the player, this will point to the player&#8217;s root structure, otherwise it will point to some NPC&#8217;s root structure.<\/p>\n\n\n\n<p>This is sufficient for our purposes in order to implement the Apocalypse system, however let&#8217;s first take a look at one of the problems I encountered after implementing it: the game rejecting my teleportitis effects.<\/p>\n\n\n\n<h2><span class=\"ez-toc-section\" id=\"No_Teleportitis_for_You!\"><\/span>No Teleportitis for You!<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p><em>Nioh 2<\/em> has an &#8220;army&#8221; of validation functions that will go off in order to prevent the character from walking out of bounds. It&#8217;s quite the interesting setup: there are a number of coordinate write functions that will only go off if we actually try to manually set our coordinates to bad values.<\/p>\n\n\n\n<p>If we disable those coordinate validation functions, we will actually see some <em>other, new<\/em> validation functions that will go off to once again correct our character&#8217;s coordinates. Kind of interesting and funny, and speaks of some very resilient code, in my opinion at least.<\/p>\n\n\n\n<p>I discovered we can actually bypass the various validation instructions by propagating the values we set our source-of-truth coordinates to, to a coordinate triplet I termed the <em>validation coordinates<\/em> &#8212; although <em>destination coordinates<\/em> could also be used as a name, I suppose. These begin at <code>[playerLocation]+0x220<\/code>.<\/p>\n\n\n\n<p>This is required in order to force a teleport in general, however I observed that teleportitis effects were still being blocked due to what else was going on when they would go off, which is typically during combat. Upon being hit by an  enemy, the player would essentially get locked into a type of animation (played in response to getting smacked) that would result in any attempted changes in movement to be rejected.<\/p>\n\n\n\n<p>So, in order to get around this, I put in a similar workaround that I implemented during some other Omnified games, which would be to force the coordinates to stick by implementing a sequence of movement frame skips, which would reject the unwanted coordinate values the game would be throwing on us during a combat animation.<\/p>\n\n\n\n<p>This is implemented within the location update code for the player, which is where the game assigns new coordinate values for the player during movement.<\/p>\n\n\n\n<h3><span class=\"ez-toc-section\" id=\"Player_Location_Update_Frame_Skip_Hook\"><\/span>Player Location Update Frame Skip Hook<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/ Processes Omnified events during execution of the location update code for the player.\n\/\/ rcx: The target location structure being updated.\n\/\/ UNIQUE AOB: 66 0F 7F 81 F0 00 00 00 C3\ndefine(omnifyLocationUpdateHook,&quot;nioh2.exe&quot;+801863)\n\nassert(omnifyLocationUpdateHook,66 0F 7F 81 F0 00 00 00)\nalloc(updateLocation,$1000,omnifyLocationUpdateHook)\nalloc(teleportLocation,16)\nalloc(framesToSkip,8)\n\nregistersymbol(omnifyLocationUpdateHook)\n\nupdateLocation:\n    pushf\n    \/\/ Since we need to update it upon a teleport occurring, the last location structure player is\n    \/\/ required for further processing.\n    push rax\n    mov rax,playerLastLocation\n    cmp [rax],0\n    pop rax\n    je updateLocationOriginalCode\n    \/\/ Only events pertaining to the player are processed here.\n    push rax\n    mov rax,playerLocation\n    cmp [rax],rcx\n    pop rax\n    jne updateLocationOriginalCode\n    \/\/ Upon a teleport, we engage in a movement frame skip sequence, this is so the desired\n    \/\/ teleport coordinates actually get committed to the player's location (and stay there); \n    \/\/ otherwise, an army of validation-related code will revert the coordinates depending on the\n    \/\/ situation.\n    cmp [framesToSkip],0\n    jg skipMovementFrame\n    push rax\n    mov rax,teleported\n    cmp [rax],1\n    pop rax\n    jne updateLocationOriginalCode\n    push rax\n    push rbx\n    push rcx\n    mov rax,teleported\n    mov [rax],0    \n    mov [framesToSkip],#25\n    mov rbx,playerLastLocation\n    mov rax,[rbx]\n    \/\/ Need to set our last location (vertically) so that proper fall damage will occur if we just\n    \/\/ got Tom Petty'd.\n    mov rcx,teleportedY\n    mov rbx,[rcx]\n    mov [rax+C8],rbx\n    pop rcx\n    pop rbx\n    pop rax    \nskipMovementFrame:    \n    dec [framesToSkip]        \n    push rax\n    push rbx        \n    push rcx\n    \/\/ Simply ignoring the updated coordinates in xmm0 is not enough, as other validation code\n    \/\/ might've already reverted our source-of-truth coordinates. So, we load up the\n    \/\/ teleport coordinates set during the Apocalypse pass.\n    mov rcx,teleportLocation\n    movdqu [rcx],xmm0\n    mov rax,teleportedX\n    mov rbx,[rax]\n    mov [rcx],rbx\n    mov rax,teleportedY\n    mov rbx,[rax]\n    mov [rcx+4],rbx\n    mov rax,teleportedZ\n    mov rbx,[rax]\n    mov [rcx+8],rbx    \n    movdqu xmm0,[rcx]\n    pop rcx\n    pop rbx\n    pop rax    \n    \/\/ Update the validation, destination coordinates as well.\n    movdqu [rcx+220],xmm0\nupdateLocationOriginalCode:\n    popf\n    movdqa [rcx+000000F0],xmm0\n    jmp updateLocationReturn\n\nomnifyLocationUpdateHook:\n    jmp updateLocation\n    nop 3\nupdateLocationReturn:\n<\/pre>\n\n\n<p>This takes care of setting the last location y-coordinate value as well upon a teleport happening.<\/p>\n\n\n\n<p>Teleportitis effects are now incredibly enjoyable and deadly.<\/p>\n\n\n\n<h2><span class=\"ez-toc-section\" id=\"Detecting_Player_As_the_Damage_Source\"><\/span>Detecting Player As the Damage Source<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>One final requirement for a perfect Apocalypse system implementation is being able to determine whether the player is the cause for damage made to an NPC, as opposed to another NPC being the source. This is something I put off at first, as the player is usually solo in this game; however, it turns out the player isn&#8217;t <em>always<\/em> solo.<\/p>\n\n\n\n<p>I didn&#8217;t want those damn &#8220;helpful&#8221; NPCs stealing my Kamehameha! Yes, that&#8217;s a thing, check the <a href=\"https:\/\/badecho.com\/index.php\/2020\/10\/19\/apocalypse-system\/\" target=\"_blank\" rel=\"noreferrer noopener\">Apocalypse article<\/a> for more information.<\/p>\n\n\n\n<p>Figuring out how to detect whether or not the player is doing damage is typically a tough task. Luckily, it didn&#8217;t take <em>too<\/em> long for me to figure out how to do this on stream. Basically, I found, via a trace, a section of code that would execute prior to the damage application code that would have one of the registers set to the damage source&#8217;s location structure.<\/p>\n\n\n\n<p>If this register was reflecting the player&#8217;s location structure, then the player is the source of the attack. So, we would just set a flag then and there and reference this flag in the main hook. Here&#8217;s the code.<\/p>\n\n\n\n<h3><span class=\"ez-toc-section\" id=\"Player_Hit_Detection_Hook\"><\/span>Player Hit Detection Hook<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/ Detects if the player is responsible for a damaging attack.\n\/\/ UNIQUE AOB: 4C 8B E8 48 85 C0 0F 84 B4\ndefine(omnifyPlayerHitDetectionHook,&quot;nioh2.exe&quot;+8B065D)\n\nassert(omnifyPlayerHitDetectionHook,4C 8B E8 48 85 C0)\nalloc(detectPlayerHit,$1000,omnifyPlayerHitDetectionHook)\nalloc(playerAttacking,8)\n\nregistersymbol(playerAttacking)\nregistersymbol(omnifyPlayerHitDetectionHook)\n\ndetectPlayerHit:\n    pushf\n    push rbx\n    mov rbx,playerLocation\n    cmp [rbx],rax\n    pop rbx\n    jne detectPlayerHitOriginalCode\n    mov [playerAttacking],1\ndetectPlayerHitOriginalCode:\n    popf\n    mov r13,rax\n    test rax,rax\n    jmp detectPlayerHitReturn\n\nomnifyPlayerHitDetectionHook:\n    jmp detectPlayerHit\n    nop \ndetectPlayerHitReturn:\n<\/pre>\n\n\n<h2><span class=\"ez-toc-section\" id=\"Apocalypse_Initiation_Hook\"><\/span>Apocalypse Initiation Hook<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Everything is now in place for us to implement the Apocalypse system into <em>Nioh 2<\/em>. The code will now be provided, which should be documented enough so that further explanation isn&#8217;t required.<\/p>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/ Initiates the Apocalypse system.\n\/\/ This is Nioh 2's damage application code.\n\/\/ [rbx+10]: Working health.\n\/\/ edi: Damage amount.\n\/\/ rbx: Target entity (i.e. [player] or an NPC) structure.\n\/\/ UNIQUE AOB: 8B 43 10 2B C7\n\/\/ Correct instruction will be single result found in nioh2.exe (not the other two DLL's).\ndefine(omnifyApocalypseHook,&quot;nioh2.exe&quot;+79C590)\n\nassert(omnifyApocalypseHook,8B 43 10 2B C7)\nalloc(initiateApocalypse,$1000,omnifyApocalypseHook)\n\nregistersymbol(omnifyApocalypseHook)\n\ninitiateApocalypse:\n    pushf\n    \/\/ An empty r12 register indicates the damage originates from falling.\n    \/\/ We don't want this to trigger Apocalypse, as it may have been Apocalypse that caused the \n    \/\/ falling...\n    cmp r12,0\n    je initiateApocalypseOriginalCode\n    \/\/ A r15 register set to 1 means we're drowning like a big dumb baby.\n    cmp r15,1\n    je initiateApocalypseOriginalCode\n    \/\/ An r8 register set to 0x400 indicates environmental fire damage.\n    cmp r8,0x400\n    je initiateApocalypseOriginalCode    \nexecuteApocalypse:\n    \/\/ Ensure the required player data structures are initialized.\n    push rax\n    mov rax,player\n    cmp [rax],0\n    pop rax\n    je initiateApocalypseOriginalCode\n    push rax\n    mov rax,playerLocation\n    cmp [rax],0\n    pop rax\n    je initiateApocalypseOriginalCode\n    \/\/ Backing up a SSE register to hold converted floating point values for the health\n    \/\/ and damage amount.\n    sub rsp,10\n    movdqu [rsp],xmm0\n    \/\/ Backing up the outputs of the Apocalypse system.\n    push rax\n    push rbx\n    \/\/ Backing up a register to hold the address pointed to by rbx, as we need to write one \n    \/\/ of our outputs to it when all is said and done.\n    push rcx    \n    mov rcx,rbx    \n    \/\/ Both Player and Enemy Apocalypse functions share the same first two parameters. \n    \/\/ Let's load them first before figuring out which subsystem to execute.\n    \/\/ We'll need to convert the working health and damage amount values from being integer types \n    \/\/ to floating point types, as this is the data type expected by the Apocalypse system.    \n    cvtsi2ss xmm0,edi    \n    \/\/ Load the damage amount parameter.\n    sub rsp,8\n    movd [rsp],xmm0\n    mov rax,[rcx+10]\n    cvtsi2ss xmm0,rax\n    \/\/ Load the working health amount parameter.\n    sub rsp,8\n    movd [rsp],xmm0    \n    \/\/ Now, we need to determine whether the player or an NPC is being damaged, and then from \n    \/\/ there execute the appropriate Apocalypse subsystem.\n    mov rax,player        \n    cmp [rax],rcx\n    je initiatePlayerApocalypse\n    jmp initiateEnemyApocalypse    \ninitiatePlayerApocalypse:        \n    \/\/ Check if the normal damage is enough (alone) to kill the player -- if it is, we forbid \n    \/\/ teleports, as we cannot move the character after he or she is dead.\n    mov rax,[rcx+10]\n    sub eax,edi\n    cmp eax,0\n    jg skipTeleportitisDisable\n    mov rax,disableTeleportitis\n    mov [rax],1\nskipTeleportitisDisable:\n    \/\/ Convert the maximum health for the player to the expected floating point form.    \n    mov rax,[rcx+8]\n    cvtsi2ss xmm0,rax\n    \/\/ Load the maximum health parameter.\n    sub rsp,8\n    movd [rsp],xmm0\n    \/\/ Align the player's location coordinate structure so it begins at our x-coordinate and pass \n    \/\/ that as the final parameter.\n    mov rax,playerLocation\n    mov rbx,[rax]\n    lea rax,[rbx+F0]\n    push rax\n    call executePlayerApocalypse\n    jmp initiateApocalypseUpdateDamage\ninitiateEnemyApocalypse:\n    \/\/ Check if the player is responsible for the attack, if not, then the damage may be from \n    \/\/ a friendly NPC, or otherwise berserk and rampaging Yokai.\n    mov rax,playerAttacking\n    cmp [rax],1\n    jne abortEnemyApocalypse\n    call executeEnemyApocalypse\n    jmp initiateApocalypseUpdateDamage\nabortEnemyApocalypse:\n    add rsp,10\n    jmp initiateApocalypseCleanup\ninitiateApocalypseUpdateDamage:\n    \/\/ To make use of the updated damage and working health amounts returned by the Apocalypse \n    \/\/ system, we'll need to convert them both back to integer form.\n    movd xmm0,eax\n    cvtss2si edi,xmm0\n    movd xmm0,ebx\n    cvtss2si ebx,xmm0\n    mov [rcx+10],ebx\n    mov rax,disableTeleportitis\n    mov [rax],0\ninitiateApocalypseCleanup:\n    mov rax,playerAttacking\n    mov [rax],0\n    pop rcx\n    pop rbx\n    pop rax\n    movdqu xmm0,[rsp]\n    add rsp,10\ninitiateApocalypseOriginalCode:\n    popf\n    mov eax,[rbx+10]\n    sub eax,edi\n    jmp initiateApocalypseReturn\n\nomnifyApocalypseHook:\n    jmp initiateApocalypse\ninitiateApocalypseReturn:\n\n\nnegativeVerticalDisplacementEnabled:\n    dd 0\n\nteleportitisDisplacementX:\n    dd (float)180.0\n\ngokuResultUpper:\n    dd #1500\n\nfatalisBloodlustDamageX:\n    dd (float)1.5\n<\/pre>\n\n\n<p>That&#8217;s it. <em>Nioh 2<\/em>, already a hard game, is now much, <em>much<\/em> harder.<\/p>\n\n\n\n<h2><span class=\"ez-toc-section\" id=\"More_Omnification_To_Come\"><\/span>More Omnification To Come<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Please remember that code posted in articles can very often end up outdated and no longer reflective of the current product. You can always find the latest version of the source code by checking out the&nbsp;<a href=\"https:\/\/github.com\/BadEcho\/core\" target=\"_blank\" rel=\"noreferrer noopener\">Bad Echo technologies repository<\/a>, with the&nbsp;<em>Nioh 2<\/em>&nbsp;target files residing&nbsp;<a href=\"https:\/\/github.com\/BadEcho\/omnified-hacks\/tree\/master\/targets\/nioh2\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p>Next up, we&#8217;ll make the enemies move with greater and deadlier speed with the implementation of the <a href=\"https:\/\/badecho.com\/index.php\/2021\/06\/18\/predator-system\/\" target=\"_blank\" rel=\"noreferrer noopener\">Predator system<\/a>.<\/p>\n\n\n\n<p>Thanks for your interest, and be sure to follow and watch the <a href=\"https:\/\/twitch.tv\/omni\" target=\"_blank\" rel=\"noreferrer noopener\">stream<\/a> if you wish to see this in action, or simply to give your support.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Onwards with the implementation of the Apocalypse system into the game Nioh 2. It is the first of the game-neutral [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9,68],"tags":[26,24,28,22],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v14.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\r\n<title>Hacking Nioh 2 - Part 2 (Apocalypse) - omni&#039;s hackpad<\/title>\r\n<meta name=\"description\" content=\"The first thing chaged in any Omnified game is the damage. Let&#039;s talk about lessons learned putting in my Apocalypse system into Nioh 2.\" \/>\r\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\r\n<link rel=\"canonical\" href=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/\" \/>\r\n<meta property=\"og:locale\" content=\"en_US\" \/>\r\n<meta property=\"og:type\" content=\"article\" \/>\r\n<meta property=\"og:title\" content=\"Hacking Nioh 2 - Part 2 (Apocalypse) - omni&#039;s hackpad\" \/>\r\n<meta property=\"og:description\" content=\"The first thing chaged in any Omnified game is the damage. Let&#039;s talk about lessons learned putting in my Apocalypse system into Nioh 2.\" \/>\r\n<meta property=\"og:url\" content=\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/\" \/>\r\n<meta property=\"og:site_name\" content=\"omni&#039;s hackpad\" \/>\r\n<meta property=\"article:published_time\" content=\"2021-09-20T12:25:09+00:00\" \/>\r\n<meta property=\"article:modified_time\" content=\"2021-09-22T12:42:30+00:00\" \/>\r\n<meta property=\"og:image\" content=\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2.jpg\" \/>\r\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\r\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/badecho.com\/#website\",\"url\":\"https:\/\/badecho.com\/\",\"name\":\"omni&#039;s hackpad\",\"description\":\"Game Code Disassembly. Omnified Modification. Madness.\",\"publisher\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/badecho.com\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/badecho.com\/wp-content\/uploads\/2021\/09\/Nioh2.jpg\",\"width\":273,\"height\":364,\"caption\":\"Nioh 2\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#webpage\",\"url\":\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/\",\"name\":\"Hacking Nioh 2 - Part 2 (Apocalypse) - omni&#039;s hackpad\",\"isPartOf\":{\"@id\":\"https:\/\/badecho.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#primaryimage\"},\"datePublished\":\"2021-09-20T12:25:09+00:00\",\"dateModified\":\"2021-09-22T12:42:30+00:00\",\"description\":\"The first thing chaged in any Omnified game is the damage. Let's talk about lessons learned putting in my Apocalypse system into Nioh 2.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/\"]}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#webpage\"},\"author\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"headline\":\"Hacking Nioh 2 &#8211; Part 2 (Apocalypse)\",\"datePublished\":\"2021-09-20T12:25:09+00:00\",\"dateModified\":\"2021-09-22T12:42:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#webpage\"},\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"image\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#primaryimage\"},\"keywords\":\"Apocalypse,Hacking,Omnified,Omnifying\",\"articleSection\":\"Games,Nioh 2\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/badecho.com\/index.php\/2021\/09\/20\/hacking-nioh-part-2\/#respond\"]}]},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\",\"name\":\"Matt Weber\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/badecho.com\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/7e345ac2708b3a41c7bd70a4a0440d41?s=96&d=mm&r=g\",\"caption\":\"Matt Weber\"},\"logo\":{\"@id\":\"https:\/\/badecho.com\/#personlogo\"}}]}<\/script>\r\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/2026"}],"collection":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/comments?post=2026"}],"version-history":[{"count":11,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/2026\/revisions"}],"predecessor-version":[{"id":2041,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/2026\/revisions\/2041"}],"wp:attachment":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/media?parent=2026"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/categories?post=2026"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/tags?post=2026"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}