M Local/NosSmooth.LocalCore/Character.cpp => Local/NosSmooth.LocalCore/Character.cpp +15 -34
  
@@ 1,47 1,28 @@
 #include "Character.h"
+#include <windows.h>
 using namespace NosSmoothCore;
-
-const BYTE WALK_OBJECT_PATTERN[] = { 0x33, 0xC9, 0x8B, 0x55, 0xFC, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 };
-const BYTE WALK_FUNCTION_PATTERN[] = { 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xEC, 0x53, 0x56, 0x57, 0x66, 0x89, 0x4D, 0xFA };
-
-LPCSTR WALK_OBJECT_MASK = "xxxxxx????x????";
-LPCSTR WALK_FUNCTION_MASK = "xxxxxxxxxxxxx";
+using namespace System;
+using namespace System::Runtime::InteropServices;
 
 Character::Character(ModuleHook moduleHook)
 {
-    auto walkFunction = moduleHook.FindPattern(WALK_FUNCTION_PATTERN, WALK_FUNCTION_MASK);
-    auto walkObject = *(unsigned int*)(moduleHook.FindPattern(WALK_OBJECT_PATTERN, WALK_OBJECT_MASK) + 0x6);
-
-    if (walkFunction == 0)
-    {
-        throw "Could not find walk function.";
-    }
-
-    if (walkObject == 0)
-    {
-        throw "Could not find player object.";
-    }
-
-    _walkFunction = walkFunction;
-    _playerObject = walkObject;
+    CharacterUnmanaged::GetInstance()->Setup(moduleHook);
 }
 
-void CallWalk(int x, int y, unsigned int playerObject, unsigned int walkFunction)
+void Character::Walk(int x, int y)
 {
     DWORD position = (y << 16) | x;
+    CharacterUnmanaged::GetInstance()->Walk(position);
+}
 
-    __asm
-    {
-        push 1
-        xor ecx, ecx
-        mov edx, position
-        mov eax, dword ptr ds : [playerObject]
-        mov eax, dword ptr ds : [eax]
-        call walkFunction
-    }
+void Character::SetWalkCallback(WalkCallback^ walkCallback)
+{
+    _walkCallback = walkCallback;
+    IntPtr functionPointer = Marshal::GetFunctionPointerForDelegate(walkCallback);
+    CharacterUnmanaged::GetInstance()->SetWalkCallback(static_cast<NativeWalkCallback>(functionPointer.ToPointer()));
 }
 
-void Character::Walk(int x, int y)
+void NosSmoothCore::Character::ResetHooks()
 {
-    CallWalk(x, y, _playerObject, _walkFunction);
-}>
\ No newline at end of file
+    CharacterUnmanaged::GetInstance()->ResetHooks();
+}
 
M Local/NosSmooth.LocalCore/Character.h => Local/NosSmooth.LocalCore/Character.h +13 -2
  
@@ 1,5 1,6 @@
 #pragma once
 #include "ModuleHook.h"
+#include "CharacterUnmanaged.h"
 
 namespace NosSmoothCore
 {
@@ 18,9 19,19 @@ namespace NosSmoothCore
 		/// <param name="x">The x coordinate to walk to.</param>
 		/// <param name="y">The y coordinate to walk to.</param>
 		void Walk(int x, int y);
+
+		/// <summary>
+		/// Registers the callback for walk function.
+		/// </summary>
+		/// <param name="walkCallback">The callback to call.</param>
+		void SetWalkCallback(WalkCallback^ walkCallback);
+
+		/// <summary>
+		/// Reset the registered hooks.
+		/// </summary>
+		void ResetHooks();
 	private:
-		unsigned int _playerObject;
-		unsigned int _walkFunction;
+		WalkCallback^ _walkCallback;
 	};
 }
 
 
A Local/NosSmooth.LocalCore/CharacterUnmanaged.cpp => Local/NosSmooth.LocalCore/CharacterUnmanaged.cpp +119 -0
  
@@ 0,0 1,119 @@
+#include "CharacterUnmanaged.h"
+#include <detours.h>
+
+using namespace NosSmoothCore;
+
+const BYTE WALK_OBJECT_PATTERN[] = { 0x33, 0xC9, 0x8B, 0x55, 0xFC, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 };
+const BYTE WALK_FUNCTION_PATTERN[] = { 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xEC, 0x53, 0x56, 0x57, 0x66, 0x89, 0x4D, 0xFA };
+
+LPCSTR WALK_OBJECT_MASK = "xxxxxx????x????";
+LPCSTR WALK_FUNCTION_MASK = "xxxxxxxxxxxxx";
+
+void CharacterWalkDetourIn()
+{
+    DWORD position = 0;
+
+    __asm
+    {
+        pushad
+        pushfd
+
+        mov position, edx
+    }
+
+    bool isAccepted = CharacterUnmanaged::GetInstance()->ExecuteWalkCallback(position);
+
+    __asm
+    {
+        popfd
+        popad
+    }
+
+    if (isAccepted) {
+        CharacterUnmanaged::GetInstance()->Walk(position);
+    }
+}
+
+// Detour entrypoint
+// declspec naked to not mess up the stack
+void __declspec(naked) CharacterWalkDetour()
+{
+    unsigned int returnPush;
+    __asm {
+        pop eax
+        pop ebx
+        mov returnPush, eax // we have to push this value on the stack before returning
+    }
+
+    CharacterWalkDetourIn();
+
+    __asm {
+        push returnPush
+        ret
+    }
+}
+
+CharacterUnmanaged::CharacterUnmanaged()
+{
+}
+
+void CharacterUnmanaged::Setup(ModuleHook moduleHook)
+{
+    auto walkFunction = moduleHook.FindPattern(WALK_FUNCTION_PATTERN, WALK_FUNCTION_MASK);
+    auto walkObject = *(unsigned int*)(moduleHook.FindPattern(WALK_OBJECT_PATTERN, WALK_OBJECT_MASK) + 0x6);
+
+    if (walkFunction == 0)
+    {
+        throw "Could not find walk function.";
+    }
+
+    if (walkObject == 0)
+    {
+        throw "Could not find player object.";
+    }
+
+    _walkFunctionAddress = walkFunction;
+    _characterObjectAddress = walkObject;
+}
+
+void CharacterUnmanaged::SetWalkCallback(NativeWalkCallback walkCallback)
+{
+    _walkCallback = walkCallback;
+    DetourTransactionBegin();
+    DetourUpdateThread(GetCurrentThread());
+    DetourAttach(&(PVOID&)_walkFunctionAddress, CharacterWalkDetour);
+    DetourTransactionCommit();
+}
+
+void CharacterUnmanaged::Walk(DWORD position)
+{
+    unsigned int walkFunction = _walkFunctionAddress;
+    unsigned int characterObject = _characterObjectAddress;
+
+    __asm
+    {
+        push 1
+        xor ecx, ecx
+        mov edx, position
+        mov eax, dword ptr ds : [characterObject]
+        mov eax, dword ptr ds : [eax]
+        call walkFunction
+    }
+}
+
+void CharacterUnmanaged::ResetHooks()
+{
+    DetourTransactionBegin();
+    DetourUpdateThread(GetCurrentThread());
+    DetourDetach(&(PVOID&)_walkFunctionAddress, CharacterWalkDetour);
+    DetourTransactionCommit();
+}
+
+bool CharacterUnmanaged::ExecuteWalkCallback(const DWORD position)
+{
+    if (_walkCallback != nullptr) {
+        return _walkCallback(position);
+    }
+
+    return true;
+}<
\ No newline at end of file
 
A Local/NosSmooth.LocalCore/CharacterUnmanaged.h => Local/NosSmooth.LocalCore/CharacterUnmanaged.h +56 -0
  
@@ 0,0 1,56 @@
+#pragma once
+#include "ModuleHook.h"
+
+namespace NosSmoothCore
+{
+	public delegate bool WalkCallback(int position);
+	typedef bool(__stdcall* NativeWalkCallback)(int position);
+
+	class CharacterUnmanaged
+	{
+	public:
+		/// <summary>
+		/// Set ups the addresses of objects.
+		/// </summary>
+		/// <param name="moduleHook">The hooking module holding the information about NostaleX.dat</param>
+		void Setup(NosSmoothCore::ModuleHook moduleHook);
+
+		/// <summary>
+		/// Starts walking to the specified x, y position
+		/// </summary>
+		/// <param name="x">The coordinate to walk to.</param>
+		void Walk(DWORD position);
+
+		/// <summary>
+		/// Registers the callback for walk function.
+		/// </summary>
+		/// <param name="walkCallback">The callback to call.</param>
+		void SetWalkCallback(NativeWalkCallback walkCallback);
+
+		/// <summary>
+		/// Reset the registered hooks.
+		/// </summary>
+		void ResetHooks();
+
+		/// <summary>
+		/// Executes the walk callback.
+		/// </summary>
+		/// <param name="position">The coordinate the user wants to walk to.</param>
+		/// <returns>Whether to accept the walk.</returns>
+		bool ExecuteWalkCallback(const DWORD position);
+
+		static CharacterUnmanaged* GetInstance()
+		{
+			static CharacterUnmanaged instance;
+			return reinterpret_cast<CharacterUnmanaged*>(&instance);
+		}
+		unsigned int _walkFunctionAddress;
+		unsigned int _characterObjectAddress;
+	private:
+		CharacterUnmanaged();
+
+
+		NativeWalkCallback _walkCallback;
+	};
+}
+
 
M Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp => Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp +11 -3
  
@@ 1,6 1,8 @@
 #include "NetworkUnmanaged.h"
 #include <detours.h>
 #include <windows.h>
+#include <chrono>
+#include <iostream>
 
 using namespace NosSmoothCore;
 
@@ 35,7 37,7 @@ void PacketSendDetour()
         popfd
         popad
     }
-
+    
     if (isAccepted) {
         NetworkUnmanaged::GetInstance()->SendPacket(packet);
     }
@@ 93,8 95,8 @@ void NetworkUnmanaged::Setup(ModuleHook moduleHook)
 
     DetourTransactionBegin();
     DetourUpdateThread(GetCurrentThread());
-    DetourAttach(&reinterpret_cast<void*&>(_sendPacketAddress), PacketSendDetour);
     DetourAttach(&(PVOID&)_receivePacketAddress, PacketReceiveDetour);
+    DetourAttach(&reinterpret_cast<void*&>(_sendPacketAddress), PacketSendDetour);
     DetourTransactionCommit();
 }
 
@@ 129,8 131,14 @@ void NetworkUnmanaged::ResetHooks()
 {
     DetourTransactionBegin();
     DetourUpdateThread(GetCurrentThread());
-    DetourDetach(&reinterpret_cast<void*&>(_sendPacketAddress), PacketSendDetour);
+    if (_sendCallback != nullptr) {
+        DetourDetach(&reinterpret_cast<void*&>(_sendPacketAddress), PacketSendDetour);
+    }
+
+    if (_receiveCallback != nullptr) {
     DetourDetach(&(PVOID&)_receivePacketAddress, PacketReceiveDetour);
+    }
+
     DetourTransactionCommit();
 }
 
 
M Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj => Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj +3 -0
  
@@ 166,6 166,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Character.h" />
+    <ClInclude Include="CharacterUnmanaged.h" />
     <ClInclude Include="ModuleHook.h" />
     <ClInclude Include="Network.h" />
     <ClInclude Include="NetworkUnmanaged.h" />
@@ 174,12 175,14 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Character.cpp" />
+    <ClCompile Include="CharacterUnmanaged.cpp" />
     <ClCompile Include="ModuleHook.cpp" />
     <ClCompile Include="Network.cpp" />
     <ClCompile Include="NetworkUnmanaged.cpp" />
     <ClCompile Include="NosSmoothCore.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="..\..\stylecop.json" />
     <None Include="packages.config" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
 
M Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters => Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters +7 -0
  
@@ 33,6 33,9 @@
     <ClInclude Include="NetworkUnmanaged.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="CharacterUnmanaged.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="NosSmoothCore.cpp">
@@ 50,8 53,12 @@
     <ClCompile Include="NetworkUnmanaged.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="CharacterUnmanaged.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
+    <None Include="..\..\stylecop.json" />
   </ItemGroup>
 </Project>=
\ No newline at end of file
 
M Local/NosSmooth.LocalCore/NosSmoothCore.cpp => Local/NosSmooth.LocalCore/NosSmoothCore.cpp +1 -0
  
@@ 30,4 30,5 @@ Network^ NosClient::GetNetwork()
 void NosClient::ResetHooks() 
 {
 	_network->ResetHooks();
+	_character->ResetHooks();
 }=
\ No newline at end of file