Skip to content
Open
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
1 change: 0 additions & 1 deletion .github/workflows/msbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,3 @@ jobs:
build/${{matrix.configuration}}/*.dll
build/${{matrix.configuration}}/ChronoType.ttf
build/${{matrix.configuration}}/ctext.json
build/${{matrix.configuration}}/loader.cfg
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## What is this?

CTExt is a replacement sqlite3.dll for the PC port of Chrono Trigger. Its main goals are to fix bugs and allow easy modding of the game.
CTExt is an extension framework for the PC port of Chrono Trigger. Its main goals are to fix bugs and allow easy modding of the game.

## What does it do?

Expand All @@ -27,18 +27,18 @@ You can compile CTExt yourself using Visual Studio 2022 or use a [pre-built rele

If you are using a pre-built release of CText, just extract the .7z archive directly into the folder where Chrono Trigger is installed.

If you choose to compile CTExt yourself, you will need to rename Chrono Trigger's existing `sqlite3.dll` to `sqlite3.orig.dll`, then copy over the compiled `sqlite3.dll`, `ctext.dll`, `ctext.json`, and `loader.cfg` files to your Chrono Trigger installation folder.
If you choose to compile CTExt yourself, copy the compiled `winmm.dll`, `ctext.dll`, `ctext.json`, and `ChronoType.ttf` files to your Chrono Trigger installation folder.

## How do I uninstall it?

Delete `sqlite3.dll` from your Chrono Trigger installation folder and rename `sqlite3.orig.dll` to `sqlite3.dll`, or remove the `ctext.dll` entry in `loader.cfg`.
Delete `winmm.dll`, `ctext.dll`, `ctext.json`, and `ChronoType.ttf` from your Chrono Trigger installation folder.

## What are all these files?

* `sqlite3.dll` is a proxy DLL for the original SQLite library that is used by Cocos2d, the game engine used by the PC port of Chrono Trigger. By using a local DLL file with the same name, we can force Chrono Trigger.exe to load our code, allowing us to inject hooks into the game. These hooks change how the code in the game works so that we can do things like redirecting file loading. `sqlite3.dll` itself does not apply any hooks and is simply a loader for other DLLs.
* `winmm.dll` is a proxy for the Windows multimedia library. By placing it next to the game executable, Chrono Trigger loads the proxy, which forwards the game's multimedia calls to the system `winmm.dll` and loads `ctext.dll`.
* `ctext.dll` is the main part of CTExt and contains all of the code and hooks.
* `ctext.json` is the configuration file for CText. With it, you can choose which built-in mods to apply, configure said mods, and set the load order of mods in the `\mods\` directory.
* `loader.cfg` is a line-separated file that tells `sqlite3.dll` which DLLs to load. By default, this file only includes `ctext.dll`, but other DLLs (like SpecialK) can be added to this list.
* `ChronoType.ttf` is the font used by CTExt's text replacement features.

## How can I help?

Expand Down
2 changes: 1 addition & 1 deletion ctext.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ VisualStudioVersion = 17.10.35122.118
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CTExt", "ctext\CTExt.vcxproj", "{74EC9696-6490-403E-97D9-C89D193B7A1E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Loader", "loader\Loader.vcxproj", "{3F7EA042-6FE1-490A-9436-62D65F73B24F}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinMM Proxy", "loader\Loader.vcxproj", "{3F7EA042-6FE1-490A-9436-62D65F73B24F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
4 changes: 2 additions & 2 deletions ctext/CTExt.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
<ClCompile Include="..\modules\minhook\src\hook.c" />
<ClCompile Include="..\modules\minhook\src\trampoline.c" />
<ClCompile Include="deps\quickjs\quickjs-amalgam.c">
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4251;4250;4146;4703</DisableSpecificWarnings>
<DisableSpecificWarnings>4251;4250;4146;4703</DisableSpecificWarnings>
</ClCompile>
<ClCompile Include="src\ctext.audio_manager.ixx" />
<ClCompile Include="src\ctext.config.ixx" />
Expand Down Expand Up @@ -182,4 +182,4 @@
</CopyFileToFolders>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>
24 changes: 9 additions & 15 deletions loader/Loader.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{3f7ea042-6fe1-490a-9436-62d65f73b24f}</ProjectGuid>
<RootNamespace>Loader</RootNamespace>
<RootNamespace>WinmmProxy</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
Expand Down Expand Up @@ -46,30 +46,29 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)\build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(Configuration)\intermediate\loader\</IntDir>
<TargetName>sqlite3</TargetName>
<TargetName>winmm</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)\build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\build\$(Configuration)\intermediate\loader\</IntDir>
<TargetName>sqlite3</TargetName>
<TargetName>winmm</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;LOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;WINMM_PROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)\modules\sqlite\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<UndefinePreprocessorDefinitions>_DEBUG</UndefinePreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>res/sqlite3.def</ModuleDefinitionFile>
<ModuleDefinitionFile>res/winmm.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
Expand All @@ -78,11 +77,10 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;LOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;WINMM_PROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)\modules\sqlite\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
Expand All @@ -91,20 +89,16 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>res/sqlite3.def</ModuleDefinitionFile>
<ModuleDefinitionFile>res/winmm.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\dllmain.cpp" />
<ClCompile Include="src\sqlite3.c" />
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="loader.cfg">
<FileType>Document</FileType>
</CopyFileToFolders>
<None Include="res\sqlite3.def" />
<None Include="res\winmm.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
10 changes: 2 additions & 8 deletions loader/Loader.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,10 @@
<ClCompile Include="src\dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\sqlite3.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="res\sqlite3.def">
<None Include="res\winmm.def">
<Filter>Source Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="loader.cfg" />
</ItemGroup>
</Project>
</Project>
1 change: 0 additions & 1 deletion loader/loader.cfg

This file was deleted.

10 changes: 0 additions & 10 deletions loader/res/sqlite3.def

This file was deleted.

5 changes: 5 additions & 0 deletions loader/res/winmm.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
LIBRARY winmm

EXPORTS
joyGetNumDevs=_joyGetNumDevs@0
joyGetPosEx=_joyGetPosEx@8
69 changes: 49 additions & 20 deletions loader/src/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -1,32 +1,61 @@
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define _WINMM_

#include <Windows.h>
#include <windows.h>
#include <mmsystem.h>

#include <fstream>
#include <string>
namespace {

using JoyGetPosExFn = MMRESULT(WINAPI*)(UINT, LPJOYINFOEX);
using JoyGetNumDevsFn = UINT(WINAPI*)();

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls(hModule);
INIT_ONCE winmmInitOnce = INIT_ONCE_STATIC_INIT;
JoyGetPosExFn realJoyGetPosEx;
JoyGetNumDevsFn realJoyGetNumDevs;

std::ifstream cfg("loader.cfg");
BOOL CALLBACK LoadSystemWinmm(PINIT_ONCE, PVOID, PVOID*) {
wchar_t path[MAX_PATH];
const UINT length = GetSystemDirectoryW(path, MAX_PATH);
if (!length || length + 11 >= MAX_PATH)
return FALSE;

std::string line;

while (std::getline(cfg, line)) {
if (line[0] == '#')
continue;
lstrcatW(path, L"\\winmm.dll");
const HMODULE module = LoadLibraryW(path);
if (!module)
return FALSE;

LoadLibraryA(line.c_str());
}
}
case DLL_PROCESS_DETACH:
break;
realJoyGetPosEx = reinterpret_cast<JoyGetPosExFn>(GetProcAddress(module, "joyGetPosEx"));
realJoyGetNumDevs = reinterpret_cast<JoyGetNumDevsFn>(GetProcAddress(module, "joyGetNumDevs"));
return realJoyGetPosEx && realJoyGetNumDevs;
}

DWORD WINAPI LoadCTExt(PVOID) {
LoadLibraryW(L"ctext.dll");
return 0;
}

} // namespace

extern "C" MMRESULT WINAPI joyGetPosEx(UINT id, LPJOYINFOEX info) {
if (!InitOnceExecuteOnce(&winmmInitOnce, LoadSystemWinmm, nullptr, nullptr))
return MMSYSERR_ERROR;

return realJoyGetPosEx(id, info);
}

extern "C" UINT WINAPI joyGetNumDevs() {
if (!InitOnceExecuteOnce(&winmmInitOnce, LoadSystemWinmm, nullptr, nullptr))
return 0;

return realJoyGetNumDevs();
}

BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID) {
if (reason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(module);
QueueUserWorkItem(LoadCTExt, nullptr, WT_EXECUTEDEFAULT);
}

return TRUE;
}
}
Loading