From 02fea4fcccf6d16beb8f959d4d2a452824f671b3 Mon Sep 17 00:00:00 2001
From: Sora <sora.x@hotmail.fr>
Date: Wed, 21 Feb 2024 02:49:55 +0100
Subject: [PATCH] Add Multiplayer support

---
 .../SADXWeightedCharacters.vcxproj            |  6 +-
 .../SADXWeightedCharacters.vcxproj.filters    |  6 ++
 SADXWeightedCharacters/mod.cpp                | 84 +++++++----------
 SADXWeightedCharacters/multiplayer.cpp        | 93 +++++++++++++++++++
 SADXWeightedCharacters/weights.h              | 36 +++++++
 5 files changed, 174 insertions(+), 51 deletions(-)
 create mode 100644 SADXWeightedCharacters/multiplayer.cpp
 create mode 100644 SADXWeightedCharacters/weights.h

diff --git a/SADXWeightedCharacters/SADXWeightedCharacters.vcxproj b/SADXWeightedCharacters/SADXWeightedCharacters.vcxproj
index 809f8ca..4fb6648 100644
--- a/SADXWeightedCharacters/SADXWeightedCharacters.vcxproj
+++ b/SADXWeightedCharacters/SADXWeightedCharacters.vcxproj
@@ -15,7 +15,7 @@
     <Keyword>Win32Proj</Keyword>
     <ProjectGuid>{31d0c5e0-0d00-45ce-a39d-915221d2fcbd}</ProjectGuid>
     <RootNamespace>SADXWeightedCharacters</RootNamespace>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>7.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -45,9 +45,11 @@
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)bin\</OutDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)bin\</OutDir>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
@@ -90,10 +92,12 @@
   <ItemGroup>
     <ClInclude Include="framework.h" />
     <ClInclude Include="pch.h" />
+    <ClInclude Include="weights.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="dllmain.cpp" />
     <ClCompile Include="mod.cpp" />
+    <ClCompile Include="multiplayer.cpp" />
     <ClCompile Include="pch.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
diff --git a/SADXWeightedCharacters/SADXWeightedCharacters.vcxproj.filters b/SADXWeightedCharacters/SADXWeightedCharacters.vcxproj.filters
index 337abe3..14ba221 100644
--- a/SADXWeightedCharacters/SADXWeightedCharacters.vcxproj.filters
+++ b/SADXWeightedCharacters/SADXWeightedCharacters.vcxproj.filters
@@ -21,6 +21,9 @@
     <ClInclude Include="pch.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="weights.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="dllmain.cpp">
@@ -32,5 +35,8 @@
     <ClCompile Include="mod.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="multiplayer.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/SADXWeightedCharacters/mod.cpp b/SADXWeightedCharacters/mod.cpp
index 785dcea..7a5248d 100644
--- a/SADXWeightedCharacters/mod.cpp
+++ b/SADXWeightedCharacters/mod.cpp
@@ -6,39 +6,13 @@
 #include "UsercallFunctionHandler.h"
 #include <map>
 #include <vector>
+#include "weights.h"
 
 using std::map;
 using std::vector;
 using std::string;
+extern bool isMPMod;
 
-struct ModelWeightInfo
-{
-	WeightInfo* weights;
-	int rightHandNode = -1;
-	int leftHandNode = -1;
-	int rightFootNode = -1;
-	int leftFootNode = -1;
-	int user0Node = -1;
-	int user1Node = -1;
-	int rightHandDir;
-	int leftHandDir;
-	int rightFootDir;
-	int leftFootDir;
-	int user0Dir;
-	int user1Dir;
-};
-
-struct CharInfo
-{
-	const char* modelPath;
-	const char* objectsArray;
-	int objectsLength;
-	const char* actionsArray;
-	int actionsLength;
-	const intptr_t* pointersArray;
-	int pointersLength;
-	map<NJS_OBJECT*, ModelWeightInfo> modelWeights;
-};
 
 const intptr_t sonicWeldPointers[] = {
 	0x49AB7E,
@@ -211,6 +185,32 @@ void ProcessWeights(CharObj2* a3, NJS_OBJECT*& object, NJS_MOTION* motion, float
 	}
 }
 
+void __cdecl ProcessVertexWelds_Check_(EntityData1* a1, EntityData2* a2, CharObj2* a3)
+{
+	NJS_OBJECT* object;
+	NJS_MOTION* motion;
+	if (a3->AnimationThing.State == 2)
+	{
+		object = a3->AnimationThing.action->object;
+		motion = a3->AnimationThing.action->motion;
+	}
+	else
+	{
+		object = a3->AnimationThing.AnimData[(unsigned __int16)a3->AnimationThing.Index].Animation->object;
+		motion = a3->AnimationThing.AnimData[(unsigned __int16)a3->AnimationThing.Index].Animation->motion;
+	}
+	if (MetalSonicFlag)
+	{
+		if (object == SONIC_OBJECTS[0])
+			object = SONIC_OBJECTS[68];
+		else if (object == SONIC_OBJECTS[66])
+			object = SONIC_OBJECTS[69];
+		else if (object == SONIC_OBJECTS[67])
+			object = SONIC_OBJECTS[70];
+	}
+	ProcessWeights(a3, object, motion, a3->AnimationThing.Frame);
+}
+
 FunctionHook<void, EntityData1*, EntityData2*, CharObj2*> ProcessVertexWelds_h(ProcessVertexWelds);
 void __cdecl ProcessVertexWelds_Check(EntityData1* a1, EntityData2* a2, CharObj2* a3)
 {
@@ -220,28 +220,10 @@ void __cdecl ProcessVertexWelds_Check(EntityData1* a1, EntityData2* a2, CharObj2
 	auto charinf = charInfos.find(id);
 	if (charinf != charInfos.end() && charinf->second.modelWeights.size() > 0)
 	{
-		NJS_OBJECT* object;
-		NJS_MOTION* motion;
-		if (a3->AnimationThing.State == 2)
-		{
-			object = a3->AnimationThing.action->object;
-			motion = a3->AnimationThing.action->motion;
-		}
-		else
-		{
-			object = a3->AnimationThing.AnimData[(unsigned __int16)a3->AnimationThing.Index].Animation->object;
-			motion = a3->AnimationThing.AnimData[(unsigned __int16)a3->AnimationThing.Index].Animation->motion;
-		}
-		if (MetalSonicFlag)
-		{
-			if (object == SONIC_OBJECTS[0])
-				object = SONIC_OBJECTS[68];
-			else if (object == SONIC_OBJECTS[66])
-				object = SONIC_OBJECTS[69];
-			else if (object == SONIC_OBJECTS[67])
-				object = SONIC_OBJECTS[70];
-		}
-		ProcessWeights(a3, object, motion, a3->AnimationThing.Frame);
+		if (isMPMod) //we don't want this whole function to run at all if MP is enabled, the code will run externally in the character display function for accurate render
+			return;
+
+		ProcessVertexWelds_Check_(a1, a2, a3);
 	}
 	else
 		ProcessVertexWelds_h.Original(a1, a2, a3);
@@ -515,6 +497,8 @@ extern "C"
 		mr_join_vertex_exec.Hook(mr_join_vertex_exec_Check);
 		mr_join_vertex_end.Hook(mr_join_vertex_end_Check);
 		ec_join_vertex_end.Hook(ec_join_vertex_end_Check);
+
+		initWeightsMultiplayer();
 	}
 
 	__declspec(dllexport) ModInfo SADXModInfo = { ModLoaderVer };
diff --git a/SADXWeightedCharacters/multiplayer.cpp b/SADXWeightedCharacters/multiplayer.cpp
new file mode 100644
index 0000000..ef80a26
--- /dev/null
+++ b/SADXWeightedCharacters/multiplayer.cpp
@@ -0,0 +1,93 @@
+#include "pch.h"
+#include "SADXModLoader.h"
+#include "FunctionHook.h"
+#include <map>
+#include <vector>
+#include "weights.h"
+
+using std::map;
+using std::vector;
+using std::string;
+
+//The multiplayer mod updates the render for each screen using the display function of the task.
+//This makes the weights rendering wrong when they are running in a main function (such as ProcessWelds in Sonic_Main)
+//We move the weights in the display of each character if the MP mod is detected so it will render properly
+
+
+#define TaskHook FunctionHook<void, task*>
+
+TaskHook SonicDisplay_t(SonicDisplay);
+TaskHook MilesDisplay_t(MilesDisplay);
+TaskHook KnuxDisplay_t(KnucklesDisplay);
+TaskHook AmyDisplay_t(AmyDisplay);
+TaskHook BigDisplay_t(BigDisplay);
+
+bool isMPMod = false;
+
+void SetWeights(task* tp)
+{
+	if (!tp || !tp->twp)
+		return;
+
+	char id = tp->twp->counter.b[1];
+
+	if (id == 0 && MetalSonicFlag)
+		id = Characters_MetalSonic;
+
+	auto charinf = charInfos.find(id);
+
+	if (charinf != charInfos.end() && charinf->second.modelWeights.size() > 0)
+	{
+		EntityData1* a1 = (EntityData1*)tp->twp;
+		EntityData2* a2 = (EntityData2*)tp->mwp;
+		if (a2)
+		{
+			CharObj2* a3 = a2->CharacterData;
+			ProcessVertexWelds_Check_(a1, a2, a3);
+		}
+	}
+}
+
+void SonicDisplay_r(task* tp)
+{
+	SetWeights(tp);
+	SonicDisplay_t.Original(tp);
+}
+
+void MilesDisplay_r(task* tp)
+{
+	SetWeights(tp);
+	MilesDisplay_t.Original(tp);
+}
+
+void KnuxDisplay_r(task* tp)
+{
+	SetWeights(tp);
+	KnuxDisplay_t.Original(tp);
+}
+
+void AmyDisplay_r(task* tp)
+{
+	SetWeights(tp);
+	AmyDisplay_t.Original(tp);
+}
+
+void BigDisplay_r(task* tp)
+{
+	SetWeights(tp);
+	BigDisplay_t.Original(tp);
+}
+
+void initWeightsMultiplayer()
+{
+	isMPMod = GetModuleHandle(L"sadx-multiplayer");
+
+	if (isMPMod)
+	{
+		SonicDisplay_t.Hook(SonicDisplay_r);
+		MilesDisplay_t.Hook(MilesDisplay_r);
+		KnuxDisplay_t.Hook(KnuxDisplay_r);
+		AmyDisplay_t.Hook(AmyDisplay_r);
+		BigDisplay_t.Hook(BigDisplay_r);
+	}
+}
\ No newline at end of file
diff --git a/SADXWeightedCharacters/weights.h b/SADXWeightedCharacters/weights.h
new file mode 100644
index 0000000..cd70014
--- /dev/null
+++ b/SADXWeightedCharacters/weights.h
@@ -0,0 +1,36 @@
+#pragma once
+
+using std::map;
+
+struct ModelWeightInfo
+{
+	WeightInfo* weights;
+	int rightHandNode = -1;
+	int leftHandNode = -1;
+	int rightFootNode = -1;
+	int leftFootNode = -1;
+	int user0Node = -1;
+	int user1Node = -1;
+	int rightHandDir;
+	int leftHandDir;
+	int rightFootDir;
+	int leftFootDir;
+	int user0Dir;
+	int user1Dir;
+};
+
+struct CharInfo
+{
+	const char* modelPath;
+	const char* objectsArray;
+	int objectsLength;
+	const char* actionsArray;
+	int actionsLength;
+	const intptr_t* pointersArray;
+	int pointersLength;
+	map<NJS_OBJECT*, ModelWeightInfo> modelWeights;
+};
+
+extern map<int, CharInfo> charInfos;
+void __cdecl ProcessVertexWelds_Check_(EntityData1* a1, EntityData2* a2, CharObj2* a3);
+void initWeightsMultiplayer();
\ No newline at end of file