Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions iw3xe.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@
<ClCompile Include="src\game\t5\mp\components\scr_parser.cpp" />
<ClCompile Include="src\game\t5\mp\main.cpp" />

<ClCompile Include="src\game\t6\sp\components\scr_parser.cpp" />
<ClCompile Include="src\game\t6\sp\main.cpp" />

<ClCompile Include="src\game\t6\mp\components\scr_parser.cpp" />
<ClCompile Include="src\game\t6\mp\main.cpp" />

<ClCompile Include="src\game\qos\sp\main.cpp" />
<ClCompile Include="src\game\qos\sp\components\scr_parser.cpp" />

Expand Down Expand Up @@ -217,6 +223,16 @@
<ClInclude Include="src\game\t5\mp\structs.h" />
<ClInclude Include="src\game\t5\mp\symbols.h" />

<ClInclude Include="src\game\t6\sp\components\scr_parser.h" />
<ClInclude Include="src\game\t6\sp\main.h" />
<ClInclude Include="src\game\t6\sp\structs.h" />
<ClInclude Include="src\game\t6\sp\symbols.h" />

<ClInclude Include="src\game\t6\mp\components\scr_parser.h" />
<ClInclude Include="src\game\t6\mp\main.h" />
<ClInclude Include="src\game\t6\mp\structs.h" />
<ClInclude Include="src\game\t6\mp\symbols.h" />

<ClInclude Include="src\game\qos\sp\main.h" />
<ClInclude Include="src\game\qos\sp\components\scr_parser.h" />
<ClInclude Include="src\game\qos\sp\structs.h" />
Expand Down
3 changes: 3 additions & 0 deletions resources/t6/_codxe/codxe.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"active_mod": "example"
}
66 changes: 66 additions & 0 deletions resources/t6/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
init()
{
level.clientid = 0;
level thread onPlayerConnect();
}

onPlayerConnect()
{
for (;;)
{
level waittill("connecting", player);

player.clientid = level.clientid;
level.clientid++;

player thread onPlayerSpawned();
}
}

onPlayerSpawned()
{
self endon("disconnect");
level endon("game_ended");

for (;;)
{
self waittill("spawned_player");

self iprintlnbold(rainbow_text("Welcome to the Example Mod !"));
}
}

rainbow_text(str)
{
if (!isDefined(str))
return "";

colors = [];
colors[colors.size] = "^1"; // Red
colors[colors.size] = "^2"; // Green
colors[colors.size] = "^3"; // Yellow
colors[colors.size] = "^4"; // Blue
colors[colors.size] = "^5"; // Cyan
colors[colors.size] = "^6"; // Pink
colors[colors.size] = "^7"; // White

rainbow = "";
colorCount = colors.size;
colorIndex = 0;

for (i = 0; i < str.size; i++)
{
ch = str[i];
if (ch == " ")
{
rainbow += ch;
continue;
}

color = colors[colorIndex % colorCount];
rainbow += color + ch;
colorIndex++;
}

return rainbow;
}
Binary file not shown.
Binary file added resources/t6/tu00000002_00000000
Binary file not shown.
19 changes: 19 additions & 0 deletions resources/xenia/plugins/415608C3/plugins.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
title_name = "Call of Duty: Black Ops II"
title_id = "415608C3" # AV-2243
#media_id = "05C7492A" # Disc (World): http://redump.org/disc/37078/

# TU18

[[plugin]]
author = "mo"
name = "iw3xe"
file = "iw3xe.xex"
hash = "B56F16A83B7E7CCC" # default.xex
is_enabled = true

[[plugin]]
author = "mo"
name = "iw3xe"
file = "iw3xe.xex"
hash = "5699D5C3866AD7DF" # default_mp.xex
is_enabled = true
9 changes: 9 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@
#include "game/t5/sp/structs.h"
#include "game/t5/sp/symbols.h"

// T6-specific includes
#include "game/t6/mp/main.h"
#include "game/t6/mp/structs.h"
#include "game/t6/mp/symbols.h"

#include "game/t6/sp/main.h"
#include "game/t6/sp/structs.h"
#include "game/t6/sp/symbols.h"

// QOS-specific includes
#include "game/qos/sp/main.h"
#include "game/qos/sp/structs.h"
Expand Down
23 changes: 23 additions & 0 deletions src/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enum GameTitleId
GAME_TITLE_ID_IW4 = 0x41560817, // Call of Duty: Modern Warfare 2
GAME_TITLE_ID_QOS = 0x415607FF, // 007: Quantum of Solace
GAME_TITLE_ID_T5 = 0x41560855, // Call of Duty: Black Ops
GAME_TITLE_ID_T6 = 0x415608C3, // Call of Duty: Black Ops II
};

void monitor_title_id()
Expand Down Expand Up @@ -145,6 +146,28 @@ void monitor_title_id()
}
return;
}
else if (current_title_id == GAME_TITLE_ID_T6)
{
if (strncmp((char *)0x8201D15C, "startSingleplayer", 17) == 0)
{
if (!in_xenia)
Sleep(1000);
xbox::show_notification(L"CODxe - T6 Singleplayer Detected");
t6::sp::init();
}
else if (strncmp((char *)0x82003580, "multiplayer", 11) == 0)
{
if (!in_xenia)
Sleep(1000);
xbox::show_notification(L"CODxe - T6 Multiplayer Detected");
t6::mp::init();
}
else
{
xbox::show_notification(L"CODxe - T6 Unsupported Executable");
}
return;
}

Sleep(50);
}
Expand Down
95 changes: 95 additions & 0 deletions src/game/t6/mp/components/scr_parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include "scr_parser.h"
#include "common.h"

namespace t6
{
namespace mp
{

// Detour Load_ScriptParseTreeAsset_Detour;
// void Load_ScriptParseTreeAsset_Hook(ScriptParseTree **a1)
// {
// ScriptParseTree *scriptParseTree = *a1;
// DbgPrint("GSCLoader: Loading script %s\n", scriptParseTree->name);

// // DbgPrint("GSCLoader: Dumping script %s\n", scriptParseTree->name);
// // std::string dumpPath = std::string(DUMP_DIR) + "\\" + scriptParseTree->name;
// // std::replace(dumpPath.begin(), dumpPath.end(), '/', '\\');
// // filesystem::write_file_to_disk(dumpPath.c_str(), scriptParseTree->buffer, scriptParseTree->len);
// // DbgPrint("GSCLoader: Dumped script to %s\n", dumpPath.c_str());

// Config config;
// LoadConfigFromFile(CONFIG_PATH, config);
// std::string modBasePath = config.GetModBasePath();
// if (!modBasePath.empty())
// {
// std::string overridePath = modBasePath + "\\" + scriptParseTree->name + "bin";
// DbgPrint("GSCLoader: Checking for override script at %s\n", overridePath.c_str());
// }

// Load_ScriptParseTreeAsset_Detour.GetOriginal<decltype(Load_ScriptParseTreeAsset)>()(a1);
// }

Detour Load_ScriptParseTreeAsset_Detour;

void Load_ScriptParseTreeAsset_Hook(ScriptParseTree **a1)
{
ScriptParseTree *scriptParseTree = *a1;
DbgPrint("GSCLoader: Loading script %s\n", scriptParseTree->name);

Config config;
LoadConfigFromFile(CONFIG_PATH, config);
std::string modBasePath = config.GetModBasePath();
if (!modBasePath.empty())
{
std::string overridePath = modBasePath + "\\" + scriptParseTree->name + "bin";
std::replace(overridePath.begin(), overridePath.end(), '/', '\\');
DbgPrint("GSCLoader: Checking for override script at %s\n", overridePath.c_str());

HANDLE file = CreateFileA(
overridePath.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (file != INVALID_HANDLE_VALUE)
{
DWORD fileSize = GetFileSize(file, NULL);
if (fileSize != INVALID_FILE_SIZE && fileSize > 0)
{
char *buffer = new char[fileSize];
DWORD bytesRead = 0;
if (ReadFile(file, buffer, fileSize, &bytesRead, NULL) && bytesRead == fileSize)
{
scriptParseTree->buffer = buffer;
scriptParseTree->len = fileSize;
DbgPrint("GSCLoader: Overridden script loaded (%d bytes)\n", fileSize);
}
else
{
delete[] buffer;
DbgPrint("GSCLoader: Failed to read override script\n");
}
}
CloseHandle(file);
}
}

Load_ScriptParseTreeAsset_Detour.GetOriginal<decltype(Load_ScriptParseTreeAsset)>()(a1);
}

scr_parser::scr_parser()
{
Load_ScriptParseTreeAsset_Detour = Detour(Load_ScriptParseTreeAsset, Load_ScriptParseTreeAsset_Hook);
Load_ScriptParseTreeAsset_Detour.Install();
}

scr_parser::~scr_parser()
{
Load_ScriptParseTreeAsset_Detour.Remove();
}
}
}
18 changes: 18 additions & 0 deletions src/game/t6/mp/components/scr_parser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include "common.h"

namespace t6
{
namespace mp
{
class scr_parser : public Module
{
public:
scr_parser();
~scr_parser();

const char *get_name() override { return "scr_parser"; };
};
}
}
32 changes: 32 additions & 0 deletions src/game/t6/mp/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "components/scr_parser.h"
#include "main.h"
#include "common.h"

namespace t6
{
namespace mp
{
std::vector<Module *> components;

void RegisterComponent(Module *module)
{
DbgPrint("T4 SP: Component registered: %s\n", module->get_name());
components.push_back(module);
}

void init()
{
DbgPrint("t6 SP: Registering modules\n");
RegisterComponent(new scr_parser());
}

void shutdown()
{
// Clean up in reverse order
for (auto it = components.rbegin(); it != components.rend(); ++it)
delete *it;

components.clear();
}
}
}
10 changes: 10 additions & 0 deletions src/game/t6/mp/main.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

namespace t6
{
namespace mp
{
void init();
void shutdown();
}
}
13 changes: 13 additions & 0 deletions src/game/t6/mp/structs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

namespace t6
{
namespace mp
{
enum scriptInstance_t : __int32
{
SCRIPTINSTANCE_SERVER = 0x0,
SCRIPTINSTANCE_CLIENT = 0x1,
};
}
}
23 changes: 23 additions & 0 deletions src/game/t6/mp/symbols.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "structs.h"

namespace t6
{
namespace mp
{
static auto Hunk_AllocateTempMemoryHighInternal = reinterpret_cast<void *(*)(int size)>(0x8248F1B0);

static auto Scr_AddSourceBuffer = reinterpret_cast<char *(*)(scriptInstance_t inst, const char *filename, const char *extFilename, const char *codePos, bool archive)>(0x82530128);

struct ScriptParseTree
{
const char *name;
int len;
char *buffer;
};

static auto Load_ScriptParseTreeAsset = reinterpret_cast<void (*)(ScriptParseTree **a1)>(0x822CA4C8);

}
}
Loading