CubeWorldMods/LocalizationMod/main.cpp

230 lines
7.7 KiB
C++

#include "main.h"
#include "CWSDK/cwsdk.h"
#ifndef NO_DEBUG_LOG
using namespace LOGGER;
char GLOBAL_BUFFER[1024];
#endif
#define CUBE_SIZE 0x57DC00
#define ADD_BASE_OFFSET (BASE_OFFSET < 0 ? 0 : BASE_OFFSET)
int BASE_OFFSET = -1;
void* Offset(void* x1, uint64_t x2) {
return (void*)((char*)x1 + x2);
}
std::vector<std::vector<std::string>> GetLocalizationProperties(){
std::ifstream configFile("Mods\\LocalizationMod\\config.txt");
if(!configFile.is_open()) {
#ifndef NO_DEBUG_LOG
logger->TraceInfo("Config not found\n");
#endif // NO_DEBUG_LOG
return std::vector<std::vector<std::string>>();
}
std::string line;
if (getline(configFile, line)) {
#ifndef NO_DEBUG_LOG
logger->TraceInfo("Config: %s\n", line.c_str());
#endif // NO_DEBUG_LOG
CCSVParse *parse = new CCSVParse();
return parse->parseCsvFile("Mods\\LocalizationMod\\" + line);
}
return std::vector<std::vector<std::string>>();
}
long long safeStoll(std::string str, long long defaultValue) {
try {
return std::stoll(str);
} catch ( ... ) {
return defaultValue;
}
}
bool startWith(const std::string &str, const std::string &head) {
return str.compare(0, head.size(), head) == 0;
}
size_t hexToDecimal(std::string hexstring, size_t defaultValue) {
if(hexstring.empty()){
return defaultValue;
}
size_t decimal;
std::stringstream ss;
ss.str(hexstring);
ss>>std::hex>>decimal;
return decimal;
}
void zeroFill(char* buf, size_t origin_len, size_t fill_len){
for(buf += origin_len;origin_len < fill_len;origin_len++){
*buf++ = '\0';
}
}
void HexOutput(const char* buf, size_t len)
{
#ifndef NO_DEBUG_LOG
char* ptr = GLOBAL_BUFFER;
for(size_t i=0; i<len; ++i)
{
unsigned char c = buf[i]; // must use unsigned char to print >128 value
if( c< 16)
{
sprintf(ptr, "0%x", c);
}
else
{
sprintf(ptr, "%x", c);
}
ptr+=2;
}
logger->TraceInfo("Hex: %s", GLOBAL_BUFFER);
#endif // NO_DEBUG_LOG
}
void FindAndReplaceString(std::vector<std::vector<std::string>> entrys){
char output[1024];
#ifndef NO_DEBUG_LOG
logger->TraceInfo("Read %d lines.", entrys.size());
#endif // NO_DEBUG_LOG
for(std::vector<std::string> item : entrys) {
if(item.size() < 3) {
continue;
}
std::string origin = item[0];
std::string target = item[1];
std::string encoding = item[2];
size_t range_begin = 0x0;
size_t range_end = CUBE_SIZE;
if(item.size() > 3) {
range_begin = hexToDecimal(item[3], range_begin);
if(item.size() > 4) {
range_end = hexToDecimal(item[4], range_end);
}
}
if(!encoding.compare("Unicode")){
bool ok;
std::u16string u16str = utf8_to_utf16be(origin, false, &ok);
size_t str_len = utf16_to_char(u16str, output);
#ifndef NO_DEBUG_LOG
HexOutput(output, str_len);
#endif
int targetOffset = nut::kmp_search((const char*)CWBase() + ADD_BASE_OFFSET + range_begin, range_end - range_begin, output, str_len);
if(targetOffset >= 0) {
if(BASE_OFFSET < 0) {
BASE_OFFSET = targetOffset;
targetOffset = 0x0;
}
#ifndef NO_DEBUG_LOG
if(targetOffset != 0x0){
logger->TraceInfo("Patching: %s", origin.c_str());
logger->TraceInfo("Search:0x%x-0x%x", range_begin, range_end);
logger->TraceInfo("Patched: %s", target.c_str());
logger->TraceInfo("Offset: 0x%x", targetOffset);
}
#endif // NO_DEBUG_LOG
std::u16string u16target = utf8_to_utf16be(target, false, &ok);
size_t target_len = utf16_to_char(u16target, output);
zeroFill(output, target_len, str_len);
HexOutput(output, target_len);
MemoryHelper::PatchMemory(Offset(CWBase(), BASE_OFFSET + range_begin + targetOffset), (void*)output, str_len);
}
#ifndef NO_DEBUG_LOG
else {
logger->TraceInfo("Patching: %s", origin.c_str());
logger->TraceInfo("Search:0x%x-0x%x", range_begin, range_end);
logger->TraceError("Not found: %s", origin.c_str());
}
#endif // NO_DEBUG_LOG
}
else if(!encoding.compare("ASCII")){
size_t str_len = utf8_to_char(origin, output);
#ifndef NO_DEBUG_LOG
HexOutput(output, str_len);
#endif // NO_DEBUG_LOG
int targetOffset = nut::kmp_search((const char*)CWBase() + range_begin, range_end - range_begin, output, str_len);
if(targetOffset >= 0) {
if(BASE_OFFSET < 0) {
BASE_OFFSET = targetOffset;
targetOffset = 0x0;
}
#ifndef NO_DEBUG_LOG
if(targetOffset != 0x0){
logger->TraceInfo("Patching: %s", origin.c_str());
logger->TraceInfo("Patched: %s", target.c_str());
logger->TraceInfo("Offset: 0x%x", targetOffset);
}
#endif // NO_DEBUG_LOG
size_t target_len = utf8_to_char(target, output);
zeroFill(output, target_len, str_len);
#ifndef NO_DEBUG_LOG
HexOutput(output, str_len);
#endif // NO_DEBUG_LOG
MemoryHelper::PatchMemory(Offset(CWBase(), BASE_OFFSET + range_begin + targetOffset), (void*)output, str_len);
}
#ifndef NO_DEBUG_LOG
else {
logger->TraceInfo("Patching: %s", origin.c_str());
logger->TraceInfo("Search:0x%x-0x%x", range_begin, range_end);
logger->TraceError("Not found: %s", origin.c_str());
}
#endif // NO_DEBUG_LOG
}
else if(!encoding.compare("ASCII_HEX")){
size_t str_len = utf8_to_char(origin.c_str(), output);
#ifndef NO_DEBUG_LOG
HexOutput(output, str_len);
#endif // NO_DEBUG_LOG
int targetOffset = nut::kmp_search((const char*)CWBase() + ADD_BASE_OFFSET + range_begin, range_end - range_begin, output, str_len);
if(targetOffset >= 0) {
if(BASE_OFFSET < 0) {
BASE_OFFSET = targetOffset;
targetOffset = 0x0;
}
#ifndef NO_DEBUG_LOG
if(targetOffset != 0x0){
logger->TraceInfo("Patching: %s", origin.c_str());
logger->TraceInfo("Patched: %s", target.c_str());
logger->TraceInfo("Offset: 0x%x", targetOffset);
}
#endif // NO_DEBUG_LOG
size_t target_len = hex_to_char(target.c_str(), output);
zeroFill(output, target_len, str_len);
#ifndef NO_DEBUG_LOG
HexOutput(output, str_len);
#endif // NO_DEBUG_LOG
MemoryHelper::PatchMemory(Offset(CWBase(), BASE_OFFSET + range_begin + targetOffset), (void*)output, str_len);
}
#ifndef NO_DEBUG_LOG
else {
logger->TraceInfo("Patching: %s", origin.c_str());
logger->TraceInfo("Search:0x%x-0x%x", range_begin, range_end);
logger->TraceError("Not found: %s", origin.c_str());
}
#endif // NO_DEBUG_LOG
}
}
}
class Mod : GenericMod {
virtual void Initialize() override {
if (BASE_OFFSET != -1) {
return;
}
BASE_OFFSET = -2;
#ifndef NO_DEBUG_LOG
logger = new CLogger(LogLevel_Info, CLogger::GetAppPathA() + "Mods\\LocalizationMod\\");
logger->ChangeLogLevel(LOGGER::LogLevel_Info);
#endif // NO_DEBUG_LOG
FindAndReplaceString(GetLocalizationProperties());
}
};
EXPORT Mod* MakeMod() {
return new Mod();
}