Compare commits

...

4 Commits

13 changed files with 232 additions and 35 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*:Zone.Identifier

View File

@ -14,17 +14,15 @@ include popnhax/Module.mk
#
zipdir := $(BUILDDIR)/zip
popnhax_version := $(shell grep "define PROGRAM_VERSION" popnhax/dllmain.cc | cut -d'"' -f2)
$(zipdir)/:
mkdir -p $@
$(BUILDDIR)/popnhax_$(popnhax_version).zip: \
build/bin/avs2_1508-32/popnhax.dll
@echo ... $@
@mkdir -p $(zipdir)
@cp -a -p build/bin/avs2_1508-32/popnhax.dll $(zipdir)
@cp -r -a -p dist/popnhax/* $(zipdir)
@cd $(zipdir) \
&& zip -r ../popnhax_$(popnhax_version).zip ./*
$(BUILDDIR)/popnhax.zip: \
build/bin/avs2_1508-32/popnhax.dll \
dist/popnhax/popnhax.xml \
dist/popnhax/D3d9.dll \
dist/popnhax/ifs_hook.dll \
| $(zipdir)/
echo ... $@
zip -j $@ $^
all: $(BUILDDIR)/popnhax.zip
all: $(BUILDDIR)/popnhax_$(popnhax_version).zip

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -15,7 +15,7 @@
<!-- Other categories -->
<!-- Bring back score challenge in the game for servers supporting it (only for kaimei onwards) -->
<score_challenge __type="bool">0</score_challenge>
<!-- Handle favorites through data_mods/<friendID>.fav files (Note: allows UNLIMITED favorites) -->
<!-- Handle favorites through data_mods/<game>.<friendID>.fav files (Note: allows UNLIMITED favorites as well as favorites without an account/server) -->
<local_favorites __type="bool">0</local_favorites>
<!-- Classic patches -->
@ -57,7 +57,7 @@
<hispeed_default_bpm __type="u16">0</hispeed_default_bpm>
<!-- IIDX-like hard gauge (start with full gauge, instant fail if gauge drops to 0) -->
<!-- Gauge details: increment: +0.1% for each cool/great/good (like spicy gauge), decrement: -9% for each bad, or -4.5% if gauge <=30% ) -->
<!-- Gauge details: increment: +0.1% for each cool/great/good (like spicy gauge), decrement: -9% for each bad, or -4.5% if gauge <=30% (like IIDX) -->
<iidx_hard_gauge __type="bool">0</iidx_hard_gauge>
<!-- Force full options by default (useful when no numpad is available) -->
<force_full_opt __type="bool">0</force_full_opt>
@ -104,11 +104,11 @@
======================================================================================== -->
<!-- Datecode and Multiboot -->
<!-- Force a different datecode than the one found in ea3-config (yyyymmdd00) -->
<force_datecode __type="str"></force_datecode>
<!-- Force a different datecode than the one found in ea3-config (yyyymmdd00), or use "auto" to let music limit decide for you if patch_db is on -->
<force_datecode __type="str">auto</force_datecode>
<!-- Also apply force_datecode to network packets -->
<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 auto conf tuning (which takes place when using popn22_yyyymmddrr.dll format and an xml without another datecode in force_datecode) -->
<disable_multiboot __type="bool">0</disable_multiboot>
<!-- Timing and lanes -->
@ -132,13 +132,13 @@
<enhanced_polling_priority __type="s8">1</enhanced_polling_priority>
<!-- Song db patches -->
<!-- Auto select patch file from data_mods folder (will detect datecode from ea3-config or force_datecode option) -->
<!-- Auto select patch file from data_mods folder based on music limit, or datecode otherwise (will detect datecode from ea3-config or force_datecode option) -->
<patch_xml_auto __type="bool">1</patch_xml_auto>
<!-- Manually set XML file containing patches (requires patch_xml_auto to be disabled) -->
<patch_xml_filename __type="str"></patch_xml_filename>
<!-- 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 (not recommended) -->
<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) (not recommended) -->
<disable_redirection __type="bool">0</disable_redirection>
<!-- Do not perform music limit checks for patch_xml_auto (not recommended) -->
<ignore_music_limit __type="bool">0</ignore_music_limit>
@ -150,10 +150,12 @@
<custom_categ_max_songid __type="u16">0</custom_categ_max_songid>
<!-- Category title for customs -->
<custom_category_title __type="str">Customs</custom_category_title>
<!-- Format used for category title (see -->
<!-- Format used for category title (in BM2DXFontScript format, refer to popnhax_tools documentation) -->
<custom_category_format __type="str">[ol:4][olc:d92f0d]%s</custom_category_format>
<!-- Format used for custom song titles on song select (Note: colors not working for kaimei and unilab, but rotation does, e.g.: * [rz:3]%s[/rz] ) -->
<!-- Format used for custom song titles on song select (Note: colors not working for kaimei and above, but rotation does, e.g. "* [rz:3]%s[/rz]" ) -->
<custom_track_title_format __type="str"></custom_track_title_format>
<!-- Optional secondary format used for older games only (Full colors supported, e.g. "[ol:4][olc:d92f0d]%s") -->
<custom_track_title_format2 __type="str"></custom_track_title_format2>
<!-- Translation -->
<!-- Disable .dict string replacements and .ips patches -->

View File

@ -63,6 +63,7 @@ struct popnhax_config {
char custom_category_title[16];
char custom_category_format[64];
char custom_track_title_format[64];
char custom_track_title_format2[64];
};
#endif

View File

@ -695,7 +695,7 @@ static bool patch_favorite_categ(const char *game_dll_fn) {
//hook result screen to replace 3 functions
{
int64_t first_loc = search(data, dllSize, "\xBF\x07\x00\x00\x00\xC6\x85\x61\xD3", 9, 0);
int64_t first_loc = search(data, dllSize, "\x10\xBF\x07\x00\x00\x00\xC6\x85", 8, 0);
if (first_loc == -1) {
LOG("popnhax: local_favorites: cannot find result screen function\n");
return false;
@ -1035,7 +1035,7 @@ bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config)
{
g_categformat = config->custom_category_format;
}
else
else
g_categformat = "%s";
if (!patch_custom_categ(dllFilename))
@ -1046,11 +1046,13 @@ bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config)
print_databases();
}
if ( config->custom_track_title_format[0] != '\0' )
{
if ( config->game_version < 26 && config->custom_track_title_format2[0] != '\0' )
g_customformat = config->custom_track_title_format2;
else if ( config->custom_track_title_format[0] != '\0' )
g_customformat = config->custom_track_title_format;
if ( g_customformat != NULL )
patch_custom_track_format(dllFilename);
}
if (config->custom_exclude_from_version)
LOG("popnhax: Customs excluded from version folders\n"); //musichax_core_init took care of it

View File

@ -201,6 +201,8 @@ PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_STR, struct popnhax_config, custom_category
"/popnhax/custom_category_format")
PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_STR, struct popnhax_config, custom_track_title_format,
"/popnhax/custom_track_title_format")
PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_STR, struct popnhax_config, custom_track_title_format2,
"/popnhax/custom_track_title_format2")
PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, local_favorites,
"/popnhax/local_favorites")
PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, ignore_music_limit,
@ -1411,10 +1413,57 @@ static bool patch_purelong()
return true;
}
static bool get_music_limit(uint32_t* limit) {
void (*real_normal0)();
void hook_normal0()
{
// getChartDifficulty returns 0xFFFFFFFF when there's no chart,
// but the game assumes there's always a normal chart so there's no check in this case
// and it returns 0... let's fix this
__asm("cmp ebx, 1\n"); //chart id
__asm("jne process_normal0\n");
__asm("cmp eax, 0\n"); //difficulty
__asm("jne process_normal0\n");
__asm("or eax, 0xFFFFFFFF\n");
__asm("process_normal0:\n");
real_normal0();
}
static bool patch_normal0()
{
DWORD dllSize = 0;
char *data = getDllData(g_game_dll_fn, &dllSize);
{
int64_t pattern_offset = search(data, dllSize, "\x83\xC4\x08\x8B\xF8\x89\x7C\x24\x3C", 9, 0);
if (pattern_offset == -1) {
LOG("popnhax: Couldn't find song list display function\n");
return false;
}
uint64_t patch_addr = (int64_t)data + pattern_offset;
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_normal0,
(void **)&real_normal0);
}
return true;
}
static bool get_music_limit(uint32_t* limit) {
// avoid doing the search multiple times
static uint32_t music_limit = 0;
if ( music_limit != 0 )
{
*limit = music_limit;
return true;
}
DWORD dllSize = 0;
char *data = getDllData(g_game_dll_fn, &dllSize);
PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew);
DWORD_PTR reloc_delta = (DWORD_PTR)((int64_t)data - headers->OptionalHeader.ImageBase);
{
int64_t string_loc = search(data, dllSize, "Illegal music no %d", 19, 0);
if (string_loc == -1) {
@ -1422,16 +1471,18 @@ static bool get_music_limit(uint32_t* limit) {
return false;
}
string_loc += reloc_delta; //reloc delta just in case
string_loc += 0x10000000; //entrypoint
char *as_hex = (char *) &string_loc;
int64_t pattern_offset = search(data, dllSize, as_hex, 4, 0);
if (pattern_offset == -1) {
LOG("popnhax: patch_db: could not retrieve music limit test function\n");
LOG("popnhax: could not retrieve music limit test function\n");
return false;
}
uint64_t patch_addr = (int64_t)data + pattern_offset - 0x1F;
*limit = *(uint32_t*)patch_addr;
music_limit = *limit;
}
return true;
}
@ -1664,6 +1715,8 @@ static bool patch_database() {
patch_purelong();
patch_normal0();
{
int64_t pattern_offset = search(data, dllSize, "\x8D\x44\x24\x10\x88\x4C\x24\x10\x88\x5C\x24\x11\x8D\x50\x01", 15, 0);
if (pattern_offset != -1) {
@ -3147,7 +3200,7 @@ static unsigned int __stdcall enhanced_polling_stats_proc(void *ctx)
if (config.enhanced_polling_priority)
{
SetThreadPriority(GetCurrentThread(), config.enhanced_polling_priority);
fprintf(stderr, "[Enhanced polling] Thread priority set to %d\n", GetThreadPriority(GetCurrentThread()));
LOG("[Enhanced polling] Thread priority set to %d\n", GetThreadPriority(GetCurrentThread()));
}
uint32_t count = 0;
@ -3236,7 +3289,7 @@ static unsigned int __stdcall enhanced_polling_proc(void *ctx)
if (config.enhanced_polling_priority)
{
SetThreadPriority(GetCurrentThread(), config.enhanced_polling_priority);
fprintf(stderr, "[Enhanced polling] Thread priority set to %d\n", GetThreadPriority(GetCurrentThread()));
LOG("[Enhanced polling] Thread priority set to %d\n", GetThreadPriority(GetCurrentThread()));
}
uint32_t curr_poll_time = 0;
@ -5430,6 +5483,116 @@ uint8_t get_version()
}
}
static bool get_music_limit_from_file(const char *filepath, uint32_t *limit){
HANDLE hFile;
HANDLE hMap;
LPVOID lpBasePtr;
LARGE_INTEGER liFileSize;
hFile = CreateFile(filepath,
GENERIC_READ, // dwDesiredAccess
0, // dwShareMode
NULL, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
0); // hTemplateFile
if (hFile == INVALID_HANDLE_VALUE) {
//file not existing is actually a good thing
return false;
}
if (!GetFileSizeEx(hFile, &liFileSize)) {
LOG("popnhax: auto_diag: GetFileSize failed with error %ld\n", GetLastError());
CloseHandle(hFile);
return false;
}
if (liFileSize.QuadPart == 0) {
LOG("popnhax: auto_diag: popn22.dll file is empty?!\n");
CloseHandle(hFile);
return false;
}
hMap = CreateFileMapping(
hFile,
NULL, // Mapping attributes
PAGE_READONLY, // Protection flags
0, // MaximumSizeHigh
0, // MaximumSizeLow
NULL); // Name
if (hMap == 0) {
LOG("popnhax: auto_diag: CreateFileMapping failed with error %ld\n", GetLastError());
CloseHandle(hFile);
return false;
}
lpBasePtr = MapViewOfFile(
hMap,
FILE_MAP_READ, // dwDesiredAccess
0, // dwFileOffsetHigh
0, // dwFileOffsetLow
0); // dwNumberOfBytesToMap
if (lpBasePtr == NULL) {
LOG("popnhax: auto_diag: MapViewOfFile failed with error %ld\n", GetLastError());
CloseHandle(hMap);
CloseHandle(hFile);
return false;
}
char *data = (char *)lpBasePtr;
int32_t delta = 0;
//first retrieve .rdata virtual and raw addresses to compute delta
{
int64_t string_loc = search(data, liFileSize.QuadPart, ".rdata", 6, 0);
if (string_loc == -1) {
LOG("popnhax: auto_diag: could not retrieve .rdata section header\n");
UnmapViewOfFile(lpBasePtr);
CloseHandle(hMap);
CloseHandle(hFile);
return false;
}
uint32_t virtual_address = *(uint32_t *)(data + string_loc + 0x0C);
uint32_t raw_address = *(uint32_t *)(data + string_loc + 0x14);
delta = virtual_address - raw_address;
}
//now attempt to find music limit from the dll
{
int64_t string_loc = search(data, liFileSize.QuadPart, "Illegal music no %d", 19, 0);
if (string_loc == -1) {
LOG("popnhax: auto_diag: could not retrieve music limit error string\n");
UnmapViewOfFile(lpBasePtr);
CloseHandle(hMap);
CloseHandle(hFile);
return false;
}
string_loc += delta; //convert to virtual address
string_loc += 0x10000000; //entrypoint
char *as_hex = (char *) &string_loc;
int64_t pattern_offset = search(data, liFileSize.QuadPart, as_hex, 4, 0);
if (pattern_offset == -1) {
LOG("popnhax: auto_diag: could not retrieve music limit test function\n");
UnmapViewOfFile(lpBasePtr);
CloseHandle(hMap);
CloseHandle(hFile);
return false;
}
uint64_t patch_addr = (int64_t)data + pattern_offset - 0x1F;
*limit = *(uint32_t*)patch_addr;
}
UnmapViewOfFile(lpBasePtr);
CloseHandle(hMap);
CloseHandle(hFile);
return true;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
@ -5489,6 +5652,30 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
if (g_game_dll_fn == NULL)
g_game_dll_fn = strdup("popn22.dll");
if ( strcmp(g_game_dll_fn, "popn22.dll") == 0 )
{
//ensure you're not running popn22.dll from the modules subfolder
char filename[MAX_PATH];
if ( GetModuleFileName(GetModuleHandle(g_game_dll_fn), filename, MAX_PATH+1) != 0 )
{
if ( strstr(filename, "\\modules\\popn22.dll") != NULL )
{
LOG("WARNING: running popn22.dll from \"modules\" subfolder is not recommended with popnhax. Please copy dlls back to contents folder\n");
}
} else {
LOG("WARNING: auto_diag: Cannot retrieve module path (%ld)\n", GetLastError());
}
//ensure there isn't a more recent version in modules subfolder
uint32_t modules_limit, current_limit;
if ( get_music_limit(&current_limit)
&& get_music_limit_from_file("modules\\popn22.dll", &modules_limit)
&& (modules_limit > current_limit) )
{
LOG("ERROR: a newer version of popn22.dll seems to be present in modules subfolder (%d vs %d songs). Please copy dlls back to contents folder\n", modules_limit, current_limit);
}
}
if (g_config_fn == NULL)
{
/* if there's an xml named like the custom game dll, it takes priority */
@ -5573,10 +5760,10 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
char translation_path[64] = "";
/* parse */
if (config.force_datecode[0] != '\0')
if ( g_datecode_override != NULL )
{
sprintf(translation_folder, "_%s%s", config.force_datecode, "_tr");
sprintf(translation_folder, "_%s%s", g_datecode_override, "_tr");
sprintf(translation_path, "%s%s", "data_mods\\", translation_folder);
if (access(translation_path, F_OK) != 0)
{

View File

@ -917,7 +917,7 @@ void parse_musicdb(const char *input_filename, const char *target, struct popnha
}
//force loading background for unilab
m->mask |= 0x100;
//m->mask |= 0x100;
if ( config->custom_categ
&& config->custom_exclude_from_version

View File

@ -73,3 +73,8 @@ int search(char *haystack, size_t haystack_size, const char *needle, size_t need
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, 0);
return res;
}
int search_debug(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) {
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, 2);
return res;
}

View File

@ -2,5 +2,6 @@
#define __SEARCH_H__
int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
int search_debug(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
#endif