forked from Popn_Tools/popnhax
translation support (.dict)
This commit is contained in:
parent
07c376893f
commit
d3bf5c7603
16
dist/popnhax/popnhax.xml
vendored
16
dist/popnhax/popnhax.xml
vendored
@ -56,20 +56,32 @@
|
|||||||
|
|
||||||
<!-- DEBUG OPTIONS FOLLOW (GENERALLY SHOULD NOT BE CHANGED UNLESS YOU KNOW WHAT YOU'RE DOING) -->
|
<!-- DEBUG OPTIONS FOLLOW (GENERALLY SHOULD NOT BE CHANGED UNLESS YOU KNOW WHAT YOU'RE DOING) -->
|
||||||
|
|
||||||
|
<!-- Datecode and Multiboot -->
|
||||||
<!-- Force a different datecode than the one found in ea3-config (yyyymmdd00) -->
|
<!-- Force a different datecode than the one found in ea3-config (yyyymmdd00) -->
|
||||||
<force_datecode __type="str"></force_datecode>
|
<force_datecode __type="str"></force_datecode>
|
||||||
<!-- Also apply force_datecode to network packets -->
|
<!-- Also apply force_datecode to network packets -->
|
||||||
<network_datecode __type="bool">1</network_datecode>
|
<network_datecode __type="bool">1</network_datecode>
|
||||||
|
<!-- Disable multiboot auto conf tuning (which takes place when using popn22_yyyymmddrr.dll format and an xml without force_datecode option) -->
|
||||||
|
<disable_multiboot __type="bool">0</disable_multiboot>
|
||||||
|
|
||||||
|
<!-- Timing and lanes -->
|
||||||
<!-- Offset the keysounds by x ms (negative is earlier) -->
|
<!-- Offset the keysounds by x ms (negative is earlier) -->
|
||||||
<keysound_offset __type="s8">0</keysound_offset>
|
<keysound_offset __type="s8">0</keysound_offset>
|
||||||
<!-- Adjust pop-kun and beam brightness (won't affect long popkuns) -->
|
<!-- Adjust pop-kun and beam brightness (won't affect long popkuns) -->
|
||||||
<beam_brightness __type="s8">0</beam_brightness>
|
<beam_brightness __type="s8">0</beam_brightness>
|
||||||
<!-- Disable the builtin frame limiter (faster/smoother animations at 120fps+) -->
|
<!-- Disable the builtin frame limiter (faster/smoother animations at 120fps+) -->
|
||||||
<fps_uncap __type="bool">0</fps_uncap>
|
<fps_uncap __type="bool">0</fps_uncap>
|
||||||
|
|
||||||
|
<!-- Song db patches -->
|
||||||
<!-- Force the newly created buffers to be the same size as the original buffers -->
|
<!-- Force the newly created buffers to be the same size as the original buffers -->
|
||||||
<disable_expansions __type="bool">0</disable_expansions>
|
<disable_expansions __type="bool">0</disable_expansions>
|
||||||
<!-- Copy the new table information over top the old tables (automatically enables disable_expansions) -->
|
<!-- Copy the new table information over top the old tables (automatically enables disable_expansions) -->
|
||||||
<disable_redirection __type="bool">0</disable_redirection>
|
<disable_redirection __type="bool">0</disable_redirection>
|
||||||
<!-- Disable multiboot auto conf tuning (which takes place when using popn22_yyyymmdd00.dll format and an xml without force_datecode option) -->
|
|
||||||
<disable_multiboot __type="bool">0</disable_multiboot>
|
<!-- Translation -->
|
||||||
|
<!-- Disable string replacements from .dict file -->
|
||||||
|
<disable_translation __type="bool">0</disable_translation>
|
||||||
|
<!-- Dump applied translations in dict_applied.txt (requires translation) -->
|
||||||
|
<dump_dict __type="bool">0</dump_dict>
|
||||||
|
|
||||||
</popnhax>
|
</popnhax>
|
||||||
|
@ -34,6 +34,8 @@ struct popnhax_config {
|
|||||||
int8_t keysound_offset;
|
int8_t keysound_offset;
|
||||||
int8_t beam_brightness;
|
int8_t beam_brightness;
|
||||||
bool fps_uncap;
|
bool fps_uncap;
|
||||||
|
bool disable_translation;
|
||||||
|
bool dump_dict;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -139,6 +139,10 @@ PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_S8, struct popnhax_config, beam_brightness,
|
|||||||
"/popnhax/beam_brightness")
|
"/popnhax/beam_brightness")
|
||||||
PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, fps_uncap,
|
PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, fps_uncap,
|
||||||
"/popnhax/fps_uncap")
|
"/popnhax/fps_uncap")
|
||||||
|
PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, disable_translation,
|
||||||
|
"/popnhax/disable_translation")
|
||||||
|
PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, dump_dict,
|
||||||
|
"/popnhax/dump_dict")
|
||||||
PSMAP_END
|
PSMAP_END
|
||||||
|
|
||||||
enum BufferIndexes {
|
enum BufferIndexes {
|
||||||
@ -632,6 +636,194 @@ bool patch_hex(const char *find, uint8_t find_size, int64_t shift, const char *r
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE *dictfile;
|
||||||
|
|
||||||
|
bool patch_sjis(const uint8_t *find, uint8_t find_size, int64_t *offset, uint8_t *replace, uint8_t replace_size) {
|
||||||
|
static DWORD dllSize = 0;
|
||||||
|
static char *data = getDllData(g_game_dll_fn, &dllSize);
|
||||||
|
static uint8_t first_offset = 0;
|
||||||
|
|
||||||
|
int64_t offset_orig = *offset;
|
||||||
|
uint64_t patch_addr;
|
||||||
|
bool valid_sjis = false;
|
||||||
|
do {
|
||||||
|
fuzzy_search_task task;
|
||||||
|
|
||||||
|
FUZZY_START(task, 1)
|
||||||
|
FUZZY_CODE(task, 0, find, find_size)
|
||||||
|
|
||||||
|
*offset = find_block(data, dllSize-*offset, &task, *offset);
|
||||||
|
if (*offset == -1) {
|
||||||
|
fprintf(stderr,"NOT FOUND\n");
|
||||||
|
*offset = offset_orig;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !first_offset )
|
||||||
|
{
|
||||||
|
if (config.dump_dict)
|
||||||
|
{
|
||||||
|
printf("popnhax: dump_dict: dump applied patches in dict_applied.txt\n");
|
||||||
|
dictfile = fopen("dict_applied.txt","wb");
|
||||||
|
}
|
||||||
|
/* limit search to a 0x100000-wide zone starting from first string found to speedup the process
|
||||||
|
* make sure to put the first string first (usually 種類順)
|
||||||
|
*/
|
||||||
|
dllSize = *offset + 0x100000;
|
||||||
|
first_offset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_addr = (int64_t)data + *offset;
|
||||||
|
|
||||||
|
/* filter out partial matches (check that there isn't a valid sjis char before our match) */
|
||||||
|
uint8_t byte1 = *(uint8_t*)(patch_addr-2);
|
||||||
|
uint8_t byte2 = *(uint8_t*)(patch_addr-1);
|
||||||
|
bool valid_first = ((0x81 <= byte1) && (byte1 <= 0x9F)) || ((0xE0 <= byte1) && (byte1 <= 0xFC));
|
||||||
|
bool valid_secnd = ((0x40 <= byte2) && (byte2 <= 0x9E)) || ((0x9F <= byte2) && (byte2 <= 0xFC));
|
||||||
|
valid_sjis = valid_first && valid_secnd;
|
||||||
|
|
||||||
|
if (valid_sjis)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Partial match at offset 0x%x, retry...\n",(uint32_t)*offset);
|
||||||
|
*offset += find_size;
|
||||||
|
}
|
||||||
|
} while (valid_sjis);
|
||||||
|
|
||||||
|
if (config.dump_dict)
|
||||||
|
fprintf(dictfile,"0x%x;%s;%s\n",(uint32_t)*offset,(char*)find,(char*)replace);
|
||||||
|
|
||||||
|
/* safety check replace is not too big */
|
||||||
|
uint8_t free_size = find_size-1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
free_size++;
|
||||||
|
}
|
||||||
|
while ( *(uint8_t *)(patch_addr+free_size) == 0 );
|
||||||
|
|
||||||
|
if ((free_size-1) < replace_size)
|
||||||
|
{
|
||||||
|
printf("WARNING: translation %s is too big, truncating to ",(char *)replace);
|
||||||
|
replace_size = free_size-1;
|
||||||
|
replace[replace_size-1] = '\0';
|
||||||
|
printf("%s\n",(char *)replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_memory(patch_addr, (char *)replace, replace_size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILE* _translation_open_dict(char *foldername)
|
||||||
|
{
|
||||||
|
char dict_filepath[64];
|
||||||
|
sprintf(dict_filepath, "%s%s%s", "data_mods\\", foldername, "\\popn22.dict");
|
||||||
|
FILE *file = fopen(dict_filepath, "rb");
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool patch_translation(FILE* dict_fp)
|
||||||
|
{
|
||||||
|
uint8_t original[128];
|
||||||
|
uint8_t translation[128];
|
||||||
|
uint8_t buffer;
|
||||||
|
int64_t curr_offset = 0;
|
||||||
|
uint8_t word_count = 0;
|
||||||
|
uint8_t orig_size = 0;
|
||||||
|
|
||||||
|
if (dict_fp == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#define STATE_WAITING 0
|
||||||
|
#define STATE_ORIGINAL 1
|
||||||
|
#define STATE_TRANSLATION 2
|
||||||
|
uint16_t err_count = 0;
|
||||||
|
uint8_t state = STATE_WAITING;
|
||||||
|
uint8_t arr_idx = 0;
|
||||||
|
while (fread(&buffer, 1, 1, dict_fp) == 1)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case STATE_WAITING:
|
||||||
|
if (buffer == ';')
|
||||||
|
{
|
||||||
|
state = STATE_ORIGINAL;
|
||||||
|
arr_idx = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Unexpected char %c\n", buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STATE_ORIGINAL:
|
||||||
|
if (buffer == ';')
|
||||||
|
{
|
||||||
|
original[arr_idx++] = '\0';
|
||||||
|
state = STATE_TRANSLATION;
|
||||||
|
orig_size = arr_idx;
|
||||||
|
arr_idx = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
original[arr_idx++] = buffer;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STATE_TRANSLATION:
|
||||||
|
if (buffer == ';')
|
||||||
|
{
|
||||||
|
/* end of word, let's patch! */
|
||||||
|
translation[arr_idx-1] = '\0'; /* strip last \n */
|
||||||
|
while ( arr_idx < orig_size )
|
||||||
|
{
|
||||||
|
translation[arr_idx++] = '\0'; /* fill with null when translation is shorter */
|
||||||
|
}
|
||||||
|
printf("%d: %s -> %s\n",++word_count,(char *)original,(char *)translation);
|
||||||
|
|
||||||
|
/* patch all occurrences */
|
||||||
|
/*curr_offset = 0;
|
||||||
|
uint8_t count = 0;
|
||||||
|
while (patch_sjis(original, orig_size, &curr_offset, translation, arr_idx-1))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
printf("%d occurrences found\n",count);
|
||||||
|
*/
|
||||||
|
if (!patch_sjis(original, orig_size, &curr_offset, translation, arr_idx-1))
|
||||||
|
{
|
||||||
|
printf("Warning: string %s (%s) not found in order, trying again.\n", (char *)original, (char *)translation);
|
||||||
|
curr_offset = 0;
|
||||||
|
if (!patch_sjis(original, orig_size, &curr_offset, translation, arr_idx-1))
|
||||||
|
{
|
||||||
|
printf("Warning: string %s not found, skipping.\n", (char *)original);
|
||||||
|
err_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state = STATE_ORIGINAL;
|
||||||
|
arr_idx = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
translation[arr_idx++] = buffer;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("popnhax: translation: patched all strings");
|
||||||
|
if (err_count)
|
||||||
|
printf(" (%u skipped strings)", err_count);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if (config.dump_dict)
|
||||||
|
fclose(dictfile);
|
||||||
|
return true;
|
||||||
|
#undef STATE_WAITING
|
||||||
|
#undef STATE_ORIGINAL
|
||||||
|
#undef STATE_TRANSLATION
|
||||||
|
}
|
||||||
|
|
||||||
char *parse_patchdb(const char *input_filename, char *base_data) {
|
char *parse_patchdb(const char *input_filename, char *base_data) {
|
||||||
const char *folder = "data_mods\\";
|
const char *folder = "data_mods\\";
|
||||||
char *input_filepath = (char*)calloc(strlen(input_filename) + strlen(folder) + 1, sizeof(char));
|
char *input_filepath = (char*)calloc(strlen(input_filename) + strlen(folder) + 1, sizeof(char));
|
||||||
@ -3395,6 +3587,32 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
|||||||
patch_datecode(config.force_datecode);
|
patch_datecode(config.force_datecode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* look for possible translation patch folder ("_yyyymmddrr_tr" for multiboot, or simply "_translation") */
|
||||||
|
if (!config.disable_translation)
|
||||||
|
{
|
||||||
|
FILE *fp = NULL;
|
||||||
|
char translation_folder[16] = "";
|
||||||
|
/* parse */
|
||||||
|
if (config.force_datecode[0] != '\0')
|
||||||
|
{
|
||||||
|
sprintf(translation_folder, "_%s%s", config.force_datecode, "_tr");
|
||||||
|
fp = _translation_open_dict(translation_folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
sprintf(translation_folder, "%s", "_translation");
|
||||||
|
fp = _translation_open_dict(translation_folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fp != NULL)
|
||||||
|
{
|
||||||
|
printf("popnhax: translation: using folder \"%s\"\n", translation_folder);
|
||||||
|
patch_translation(fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (config.practice_mode) {
|
if (config.practice_mode) {
|
||||||
patch_practice_mode();
|
patch_practice_mode();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user