Skip to content

Commit

Permalink
New Text plugin. (#104)
Browse files Browse the repository at this point in the history
New Text plugin
  • Loading branch information
MiranDMC authored Mar 21, 2024
1 parent d41d80d commit 130f720
Show file tree
Hide file tree
Showing 49 changed files with 1,840 additions and 634 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@
- new opcode **2405 ([is_script_running](https://library.sannybuilder.com/#/sa/memory/2405))**
- new opcode **2406 ([get_script_struct_from_filename](https://library.sannybuilder.com/#/sa/memory/2406))**
- new opcode **2407 ([is_memory_equal](https://library.sannybuilder.com/#/sa/memory/2407))**
- new [Text](https://github.com/cleolibrary/CLEO5/tree/master/cleo_plugins/Text) plugin
- text related opcodes moved from CLEO core into separated plugin
- new opcode **2600 ([is_text_empty](https://library.sannybuilder.com/#/sa/text/2600))**
- new opcode **2601 ([is_text_equal](https://library.sannybuilder.com/#/sa/text/2601))**
- new opcode **2602 ([is_text_in_text](https://library.sannybuilder.com/#/sa/text/2602))**
- new opcode **2603 ([is_text_prefix](https://library.sannybuilder.com/#/sa/text/2603))**
- new opcode **2604 ([is_text_suffix](https://library.sannybuilder.com/#/sa/text/2604))**
- new and updated opcodes
- implemented support for **memory pointer string** arguments for all game's native opcodes
- **0B1E ([sign_extend](https://library.sannybuilder.com/#/sa/bitwise/0B1E))**
- **0DD5 ([get_game_platform](https://library.sannybuilder.com/#/sa/CLEO/0DD5))**
- **2002 ([cleo_return_with](https://library.sannybuilder.com/#/sa/CLEO/2002))**
Expand Down Expand Up @@ -99,6 +107,8 @@
- new SDK method: CLEO_GetScriptWorkDir
- new SDK method: CLEO_SetScriptWorkDir
- new SDK method: CLEO_ResolvePath
- new SDK method: CLEO_ListDirectory
- new SDK method: CLEO_ListDirectoryFree
- new SDK method: CLEO_GetScriptByName
- new SDK method: CLEO_GetScriptByFilename
- new SDK method: CLEO_GetScriptDebugMode
Expand Down
10 changes: 8 additions & 2 deletions CLEO5.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
<ClCompile Include="source\CModuleSystem.cpp" />
<ClCompile Include="source\crc32.cpp" />
<ClCompile Include="source\CScriptEngine.cpp" />
<ClCompile Include="source\CTextManager.cpp" />
<ClCompile Include="source\dllmain.cpp" />
<ClCompile Include="source\OpcodeInfoDatabase.cpp" />
<ClCompile Include="source\PluginSdkExternals.cpp" />
Expand All @@ -60,6 +59,14 @@
<ClCompile Include="$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\CPools.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\CCheat.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\CModelInfo.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="cleo_sdk\CLEO.h" />
Expand All @@ -75,7 +82,6 @@
<ClInclude Include="source\CPluginSystem.h" />
<ClInclude Include="source\crc32.h" />
<ClInclude Include="source\CScriptEngine.h" />
<ClInclude Include="source\CTextManager.h" />
<ClInclude Include="source\FileEnumerator.h" />
<ClInclude Include="source\Mem.h" />
<ClInclude Include="source\OpcodeInfoDatabase.h" />
Expand Down
6 changes: 6 additions & 0 deletions cleo_plugins/CLEO_Plugins.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MemoryOperations", "MemoryO
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Audio", "Audio\Audio.vcxproj", "{897344A5-1AF1-493A-8B0B-196C0423D5DA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Text", "Text\Text.vcxproj", "{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Expand Down Expand Up @@ -45,6 +47,10 @@ Global
{897344A5-1AF1-493A-8B0B-196C0423D5DA}.Debug|x86.Build.0 = Debug|Win32
{897344A5-1AF1-493A-8B0B-196C0423D5DA}.Release|x86.ActiveCfg = Release|Win32
{897344A5-1AF1-493A-8B0B-196C0423D5DA}.Release|x86.Build.0 = Release|Win32
{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}.Debug|x86.ActiveCfg = Debug|Win32
{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}.Debug|x86.Build.0 = Debug|Win32
{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}.Release|x86.ActiveCfg = Release|Win32
{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
9 changes: 2 additions & 7 deletions cleo_plugins/FileSystemOperations/FileSystemOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,12 +290,7 @@ class FileSystemOperations
static OpcodeResult WINAPI opcode_0AD7(CRunningScript* thread)
{
auto handle = READ_FILE_HANDLE_PARAM();

char* buffer = nullptr;
int bufferSize = 0;
DWORD needsTerminator = TRUE;
CLEO_ReadStringParamWriteBuffer(thread, &buffer, &bufferSize, &needsTerminator);

auto result = OPCODE_READ_PARAM_OUTPUT_VAR_STRING();
auto size = OPCODE_READ_PARAM_INT();

if (size < 0)
Expand All @@ -311,7 +306,7 @@ class FileSystemOperations
}

// use caller's size argument, ignoring actual target type size. Intended for legacy reasons.
bool ok = File::readString(handle, buffer, size) != nullptr;
bool ok = File::readString(handle, result.data, size) != nullptr;

OPCODE_CONDITION_RESULT(ok);
return OR_CONTINUE;
Expand Down
149 changes: 23 additions & 126 deletions source/CTextManager.cpp → cleo_plugins/Text/CTextManager.cpp
Original file line number Diff line number Diff line change
@@ -1,113 +1,26 @@
#include "stdafx.h"

#include "CTextManager.h"
#include "CleoBase.h"
#include "FileEnumerator.h"
#include "..\cleo_sdk\CLEO_Utils.h"
#include "CFileMgr.h"
#include "CText.h"
#include <wtypes.h>
#include <direct.h>
#include <filesystem>
#include <fstream>
#include <set>
#include <sstream>
#include <direct.h>
#include <string>

namespace FS = std::filesystem;

namespace CLEO
{
CText *gameTexts;
char *cheatString;
BYTE *mpackNumber;

void(__cdecl * _PrintHelp)(const char *, bool sound, bool permanent, bool brief);
void(__cdecl * _PrintBig)(const char *, unsigned time, unsigned style);
void(__cdecl * _Print) (const char *, unsigned time, bool flag1, bool flag2);
void(__cdecl * _PrintNow) (const char *, unsigned time, bool flag1, bool flag2);
const char* (__fastcall * CText__Get)(CText*, int dummy, const char*);
DWORD _CText__TKey__locate;

char message_buf_big[7][MAX_STR_LEN];
char message_buf_low[MAX_STR_LEN];
char message_buf_high[MAX_STR_LEN];

const char * __fastcall CText__TKey__locate(CText__TKey *key, int dummy, const char *gxt, bool& found)
{
const char * result;
_asm
{
mov ecx, key
push found
push gxt
call _CText__TKey__locate
mov result, eax
}
return result;
}

void PrintHelp(const char *text, bool bPermanent, bool bBeep, bool bAddBrief)
{
_PrintHelp(text, bBeep, bPermanent, bAddBrief);
}

void ClearHelp()
{
_PrintHelp(nullptr, false, false, false);
}

void PrintBig(const char *text, unsigned time, unsigned style)
{
strcpy(message_buf_big[style - 1], text);
_PrintBig(message_buf_big[style - 1], time, style - 1);
}

void Print(const char *text, unsigned time)
{
strcpy(message_buf_low, text);
_Print(message_buf_low, time, false, false);
}

void PrintNow(const char *text, unsigned time)
{
strcpy(message_buf_high, text);
_PrintNow(message_buf_high, time, false, false);
}

bool TestCheat(const char* cheat)
{
char *c = cheatString;
char buf[30];
strcpy(buf, cheat);
char *s = _strrev(buf);
if (_strnicmp(s, c, strlen(s))) return false;
cheatString[0] = 0;
return true;
}

const char * __fastcall CText__locate(CText *text, int dummy, const char *gxt)
{
bool bFound;
const char *szResult;

if ((*gxt == '\0') || (*gxt == ' ')) return "";

szResult = GetInstance().TextManager.LocateFxt(gxt);
if (szResult) return szResult;

szResult = CText__TKey__locate(&text->tkeyMain, 0, gxt, bFound);

if (!bFound)
{
if (text->missionTableLoaded || *mpackNumber || text->haveTabl)
{
szResult = CText__TKey__locate(&text->tkeyMission, 0, gxt, bFound);
if (!bFound) return "";
//else TRACE("Failed to find used text label '%s'", gxt);
}
}
return szResult;
}

CTextManager::CTextManager() : fxts(1, crc32FromUpcaseStdString)
{
}

const char* CTextManager::Get(const char* key)
{
return CText__Get(gameTexts, 0, key);
return TheText.Get(key);
}

bool CTextManager::AddFxt(const char *key, const char *value, bool dynamic)
Expand Down Expand Up @@ -154,19 +67,15 @@ namespace CLEO
void CTextManager::ClearDynamicFxts()
{
TRACE("Deleting dynamic fxts...");
// size_t count = 0, total = fxts.size();
for (auto it = fxts.begin(); it != fxts.end();)
{
if (!it->second->is_static)
{
delete it->second;
fxts.erase(it++);
// ++count;
}
else ++it;
}
// TRACE("Deleting finished, %d elements erased, %d elements left",
// count, total - count);
}

CTextManager::~CTextManager()
Expand All @@ -179,50 +88,36 @@ namespace CLEO
fxts.erase(it++);
++count;
}
// TRACE("Deleting finished, %d elements erased", count);
}

void CTextManager::LoadFxts()
{
// create FXT directory if not present yet
FS::create_directory(FS::path(CFileMgr::ms_rootDirName).append("cleo\\cleo_text"));

// load whole FXT files directory
auto path = FS::path(Filepath_Cleo).append("cleo_text").string();
FilesWalk(path.c_str(), ".fxt", [this](const char* fullPath, const char* filename)
auto list = CLEO::CLEO_ListDirectory(nullptr, "cleo\\cleo_text\\*.fxt", false, true);
for (DWORD i = 0; i < list.count; i++)
{
TRACE("Parsing FXT file %s", fullPath);
try
{
std::ifstream stream(fullPath);
std::ifstream stream(list.paths[i]);
auto result = ParseFxtFile(stream);
TRACE("Added %d new FXT entries from file %s", result, fullPath);
TRACE("Added %d new FXT entries from file %s", result, list.paths[i]);
}
catch (std::exception& ex)
{
LOG_WARNING(0, "Loading of FXT file '%s' failed: \n%s", fullPath, ex.what());
LOG_WARNING(0, "Loading of FXT file '%s' failed: \n%s", list.paths[i], ex.what());
}
});
}
CLEO::CLEO_ListDirectoryFree(list);
}

void CTextManager::Clear()
{
fxts.clear();
}

void CTextManager::Inject(CCodeInjector& inj)
{
TRACE("Injecting TextManager...");
CGameVersionManager& gvm = GetInstance().VersionManager;
_PrintHelp = gvm.TranslateMemoryAddress(MA_TEXT_BOX_FUNCTION);
_PrintBig = gvm.TranslateMemoryAddress(MA_STYLED_TEXT_FUNCTION);
_Print = gvm.TranslateMemoryAddress(MA_TEXT_LOW_PRIORITY_FUNCTION);
_PrintNow = gvm.TranslateMemoryAddress(MA_TEXT_HIGH_PRIORITY_FUNCTION);
_CText__TKey__locate = gvm.TranslateMemoryAddress(MA_CTEXT_TKEY_LOCATE_FUNCTION);
gameTexts = gvm.TranslateMemoryAddress(MA_GAME_TEXTS);
cheatString = gvm.TranslateMemoryAddress(MA_CHEAT_STRING);
mpackNumber = gvm.TranslateMemoryAddress(MA_MPACK_NUMBER);
CText__Get = gvm.TranslateMemoryAddress(MA_CALL_CTEXT_LOCATE);
inj.InjectFunction(CText__locate, CText__Get);
}

CTextManager::FxtEntry::FxtEntry(const char *_text, bool _static) : text(_text), is_static(_static)
{
}
Expand All @@ -237,8 +132,10 @@ namespace CLEO
while (true)
{
if (stream.eof()) break;

stream.getline(buf, sizeof(buf));
if (stream.fail()) break;

// parse extracted line
key_start = key_iterator = buf;
while (*key_iterator)
Expand Down
20 changes: 4 additions & 16 deletions source/CTextManager.h → cleo_plugins/Text/CTextManager.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#pragma once
#include "stdafx.h"
#include "CCodeInjector.h"
#include "CText.h"
#include "crc32.h"
#include <string>
#include <unordered_map>

namespace CLEO
{
class CTextManager : VInjectible
class CTextManager
{
class FxtEntry
{
Expand All @@ -17,11 +16,11 @@ namespace CLEO
FxtEntry(const char *_text, bool _static = false);
};

typedef std::unordered_map<std::string, FxtEntry *,
decltype(&crc32FromUpcaseStdString)> fxt_map_type;
typedef std::unordered_map<std::string, FxtEntry *, decltype(&crc32FromUpcaseStdString)> fxt_map_type;
typedef fxt_map_type::iterator fxt_iterator;
typedef fxt_map_type::const_iterator const_fxt_iterator;
fxt_map_type fxts;

public:
CTextManager();
~CTextManager();
Expand All @@ -37,16 +36,5 @@ namespace CLEO
// erase all fxts, added by scripts
void ClearDynamicFxts();
size_t ParseFxtFile(std::istream& stream);
virtual void Inject(CCodeInjector& inj);
};

void PrintHelp(const char *text, bool bPermanent = false, bool bBeep = true, bool bAddBrief = false);
void ClearHelp();
void PrintBig(const char *text, unsigned time, unsigned style);
void Print(const char *text, unsigned time);
void PrintNow(const char *text, unsigned time);

bool TestCheat(const char* cheat);
extern CText * gameTexts;
const char * __fastcall CText__locate(CText *text, int dummy, const char *gxt);
}
Loading

0 comments on commit 130f720

Please sign in to comment.