Compare commits

...

23 Commits

Author SHA1 Message Date
d17bd63f3a fix local favorite end of credit crash with guest 2024-06-06 09:55:31 +02:00
03104c4ae9 result screen retire/retry sound ok 2024-06-06 00:33:57 +02:00
65f9c02f65 backtosongselect sound ok 2024-06-06 00:19:59 +02:00
a00cbd6daa indent 2024-06-05 20:44:27 +02:00
3a57387e6a wip backtosongselect fix 2024-06-05 20:43:39 +02:00
d483cd61d7 wip sound when pfree leave 2024-06-05 00:39:18 +02:00
cce17f9483 auto hispeed reset to default bpm between credits 2024-06-04 21:59:52 +02:00
bed5eed9b6 high_framerate_limiter 2024-06-03 21:05:29 +02:00
87de9ed78a high framerate fps 2024-06-03 21:05:29 +02:00
f1a78c8469 high framerate patch 2024-06-03 21:05:29 +02:00
94377ea218 exclude custom folder with _ or _exclude file 2024-06-03 21:05:29 +02:00
3c20bef186 rename subcateg via _name.txt 2024-06-03 21:05:29 +02:00
6a21121e8b remove max_song_id, add partial_entries and exclude_omni 2024-06-03 21:05:29 +02:00
fc4a817824 move subcateg creation to loader.cc 2024-06-03 21:05:29 +02:00
899b311281 add BST for customs 2024-06-03 21:05:29 +02:00
989350e051 wip better custom detection 2024-06-03 21:05:29 +02:00
6f2a340359 wip exclude customs by prepending _ 2024-06-03 21:05:29 +02:00
2b7ba52f1a fix enhanced polling judgement correction 2024-06-03 21:05:29 +02:00
c39bce4e1f fix auto hispeed soflan retry quirks 2024-06-03 21:05:29 +02:00
eb56b39d1b fix auto hispeed random x1.0 bug 2024-06-03 21:05:29 +02:00
aa7505206c enhance custom popkuns handling for record mode 2024-06-03 21:05:29 +02:00
27d6453bd3 r2nk226: popkun change 2024-06-03 21:05:29 +02:00
ae12d608cd r2nk226: record mode, practice mode enhanced 2024-06-03 21:05:04 +02:00
10 changed files with 2918 additions and 613 deletions

Binary file not shown.

View File

@ -18,6 +18,10 @@
<!-- 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>
<!-- Framerate -->
<!-- Fix animation speed at higher framerate for a smoother experience (lower visual latency) -->
<high_framerate __type="bool">0</high_framerate>
<!-- Classic patches -->
<!-- Prevent crash on boot when using a different default audio source (aka HDMI audio patch) -->
<audio_source_fix __type="bool">0</audio_source_fix>
@ -95,7 +99,6 @@
<!-- PLEASE USE OFFLINE ONLY -->
<practice_mode __type="bool">0</practice_mode>
<!-- Press 9 on option select screen to go back to song selection (requires quick_retire) -->
<!-- Note: causes issues with sounds on song select -->
<back_to_song_select __type="bool">0</back_to_song_select>
@ -120,8 +123,6 @@
<keysound_offset __type="s8">0</keysound_offset>
<!-- Adjust pop-kun and beam brightness (won't affect long popkuns) -->
<beam_brightness __type="s8">0</beam_brightness>
<!-- Disable the builtin frame limiter (faster/smoother animations at 120fps+) -->
<fps_uncap __type="bool">0</fps_uncap>
<!-- 1000Hz polling thread priority (for enhanced_polling only, might cause crashes on some systems if set too high)
values THREAD_PRIORITY_LOWEST -2
THREAD_PRIORITY_BELOW_NORMAL -1
@ -131,7 +132,15 @@
THREAD_PRIORITY_TIME_CRITICAL 15 -->
<enhanced_polling_priority __type="s8">1</enhanced_polling_priority>
<!-- Song db patches -->
<!-- Framerate -->
<!-- Reference fps value for high_framerate animation speed (0: use monitor refreshrate and disable frame limiter) -->
<high_framerate_fps __type="u16">0</high_framerate_fps>
<!-- Tune the builtin frame limiter the closest to high_framerate_fps -->
<high_framerate_limiter __type="bool">1</high_framerate_limiter>
<!-- Disable the builtin frame limiter -->
<fps_uncap __type="bool">0</fps_uncap>
<!-- Song db patches (requires patch_db) -->
<!-- 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) -->
@ -143,11 +152,13 @@
<!-- Do not perform music limit checks for patch_xml_auto (not recommended) -->
<ignore_music_limit __type="bool">0</ignore_music_limit>
<!-- Custom category options -->
<!-- minimum songid for a song to be seen as "custom" -->
<custom_categ_min_songid __type="u16">4000</custom_categ_min_songid>
<!-- maximum songid for a song to be seen as "custom" (0 = no limit, not recommended since "random" category will use fake song ids in the 65400+ range) -->
<custom_categ_max_songid __type="u16">65400</custom_categ_max_songid>
<!-- Custom category options (requires patch_db) -->
<!-- Also exclude omnimix (song id < 3000) tracks from version/level (requires custom_exclude_from_level or custom_exclude_from_version) -->
<exclude_omni __type="bool">0</exclude_omni>
<!-- Any new chart added to an existing song moves the song to the customs folder -->
<partial_entries __type="bool">0</partial_entries>
<!-- Minimum songid for a song to be seen as "custom" (e.g. use 4000 for real customs only) -->
<custom_categ_min_songid __type="u16">0</custom_categ_min_songid>
<!-- Category title for customs -->
<custom_category_title __type="str">Customs</custom_category_title>
<!-- Format used for category title (in BM2DXFontScript format, refer to BM2DXFontScript.md in popnhax_tools repo) -->

View File

@ -17,7 +17,6 @@ struct popnhax_config {
bool score_challenge;
uint8_t custom_categ;
uint16_t custom_categ_min_songid;
uint16_t custom_categ_max_songid;
bool custom_exclude_from_version;
bool custom_exclude_from_level;
bool force_hd_timing;
@ -64,6 +63,11 @@ struct popnhax_config {
char custom_category_format[64];
char custom_track_title_format[64];
char custom_track_title_format2[64];
bool exclude_omni;
bool partial_entries;
bool high_framerate;
bool high_framerate_limiter;
uint16_t high_framerate_fps;
};
#endif

View File

@ -19,14 +19,10 @@
#include "minhook/hde32.h"
#include "minhook/include/MinHook.h"
#include "custom_categs.h"
#define F_OK 0
uint8_t g_game_version;
uint32_t g_playerdata_ptr_addr; //pointer to the playerdata memory zone (offset 0x08 is popn friend ID as ascii (12 char long), offset 0x1A5 is "is logged in" flag)
char *g_current_friendid;
uint32_t g_current_songid;
void (*add_song_in_list)();
//game code takes array start address from offset 0xC and the address after the list end from offset 0x10
typedef struct songlist_s {
uint32_t dummy[3];
@ -34,9 +30,17 @@ typedef struct songlist_s {
uint32_t array_end;
} songlist_t;
uint8_t g_game_version;
uint32_t g_playerdata_ptr_addr; //pointer to the playerdata memory zone (offset 0x08 is popn friend ID as ascii (12 char long), offset 0x1A5 is "is logged in" flag)
char *g_current_friendid;
uint32_t g_current_songid;
bst_t *g_customs_bst = NULL;
bool g_exclude_omni = false;
void (*add_song_in_list)();
bool g_subcategmode = false;
uint32_t g_min_id = 4000;
uint32_t g_max_id = 0;
const char *g_categicon;
const char *g_categformat;
@ -55,6 +59,16 @@ uint32_t favorites_count = 0;
songlist_t favorites_struct;
uint32_t favorites_struct_addr = (uint32_t)&favorites_struct;
bool is_a_custom(uint32_t songid)
{
return (bst_search(g_customs_bst, songid) != NULL);
}
bool is_excluded_from_level(uint32_t songid)
{
return ( is_a_custom(songid) && ( g_exclude_omni || songid >= 3000 ) );
}
void add_song_to_favorites()
{
favorites = (uint32_t *) realloc(favorites, sizeof(uint32_t)*(favorites_count+5));
@ -233,12 +247,6 @@ uint32_t songlist_count = 0;
songlist_t songlist_struct;
uint32_t songlist_struct_addr = (uint32_t)&songlist_struct;
typedef struct {
char *name;
uint32_t size;
uint32_t *songlist;
} subcategory_s;
subcategory_s* subcategories;
uint32_t g_subcateg_count = 0;
//subcategories[0] is the "ALL SONGS" virtual subcategory,
@ -256,10 +264,9 @@ static bool subcateg_has_songid(uint32_t songid, subcategory_s* subcateg)
return false;
}
static void add_song_to_subcateg(uint32_t songid, subcategory_s* subcateg)
void add_song_to_subcateg(uint32_t songid, subcategory_s* subcateg)
{
if ( songid >= g_min_id
&& (g_max_id == 0 || songid <= g_max_id)
if ( is_a_custom(songid)
&& !subcateg_has_songid(songid, subcateg) )
{
subcateg->songlist = (uint32_t *) realloc(subcateg->songlist, sizeof(uint32_t)*(++subcateg->size));
@ -275,7 +282,7 @@ static void add_song_to_subcateg(uint32_t songid, subcategory_s* subcateg)
}
}
static subcategory_s* get_subcateg(char *title)
subcategory_s* get_subcateg(const char *title)
{
for (uint32_t i = 0; i < g_subcateg_count; i++)
{
@ -283,7 +290,15 @@ static subcategory_s* get_subcateg(char *title)
if (strcmp(title, subcategories[i+1].name) == 0)
return &(subcategories[i+1]);
}
return NULL;
//not found, allocate a new one
subcategories = (subcategory_s*)realloc(subcategories, sizeof(subcategory_s)*((++g_subcateg_count)+1));
subcategory_s *subcateg = &(subcategories[g_subcateg_count]);
subcateg->name = strdup(title);
subcateg->songlist = NULL;
subcateg->size = 0;
return subcateg;
}
void (*categ_inject_songlist)();
@ -502,15 +517,19 @@ void hook_categ_reinit_songlist()
real_categ_reinit_songlist();
}
// in simple category mode, the game itself builds the full list by checking songids on the fly
void (*real_categ_build_songlist)();
void hook_categ_build_songlist()
{
__asm("cmp eax, _g_min_id\n");
__asm("jb categ_skip_add\n");
__asm("cmp dword ptr _g_max_id, 0\n");
__asm("je add_my_song\n");
__asm("cmp eax, _g_max_id\n");
__asm("ja categ_skip_add\n");
__asm("push edx\n");
__asm("push ecx\n");
__asm("push eax\n");
__asm("call %P0" : : "i"(is_a_custom));
__asm("test eax, eax\n");
__asm("pop eax\n");
__asm("pop ecx\n");
__asm("pop edx\n");
__asm("jz categ_skip_add\n");
__asm("add_my_song:\n");
__asm("push eax\n");
@ -570,12 +589,16 @@ void hook_song_printf()
__asm("push eax\n");
__asm("push ebx\n");
__asm("mov eax, [esp+0x50]\n");
__asm("cmp eax, _g_min_id\n");
__asm("jb print_regular_song\n");
__asm("cmp dword ptr _g_max_id, 0\n");
__asm("je print_custom_song\n");
__asm("cmp eax, _g_max_id\n");
__asm("ja print_regular_song\n");
__asm("push ecx\n");
__asm("push edx\n");
__asm("push eax\n");
__asm("call %P0" : : "i"(is_a_custom));
__asm("test eax, eax\n");
__asm("pop eax\n");
__asm("pop edx\n");
__asm("pop ecx\n");
__asm("jz print_regular_song\n");
__asm("print_custom_song:\n");
@ -595,12 +618,16 @@ void hook_artist_printf()
__asm("push eax\n");
__asm("push ebx\n");
__asm("mov eax, [esp+0x50]\n");
__asm("cmp eax, _g_min_id\n");
__asm("jb print_regular_artist\n");
__asm("cmp dword ptr _g_max_id, 0\n");
__asm("je print_custom_artist\n");
__asm("cmp eax, _g_max_id\n");
__asm("ja print_regular_artist\n");
__asm("push ecx\n");
__asm("push edx\n");
__asm("push eax\n");
__asm("call %P0" : : "i"(is_a_custom));
__asm("test eax, eax\n");
__asm("pop eax\n");
__asm("pop edx\n");
__asm("pop ecx\n");
__asm("jz print_regular_artist\n");
__asm("print_custom_artist:\n");
@ -653,6 +680,31 @@ static bool patch_custom_track_format(const char *game_dll_fn) {
return true;
}
void (*real_remove_fake_login)();
void hook_remove_fake_login()
{
//getPlayerDataAddr was just called so eax contains _playerdata_addr
__asm("push ebx\n");
__asm("push ecx\n");
__asm("lea ebx, [eax+0x1A5]\n"); //login status offset
__asm("lea ecx, [eax+0x08]\n"); //friendid offset
__asm("mov ecx, [ecx]\n");
__asm("cmp ecx, 0x61666564\n"); //defa
__asm("jne skip_remove_login\n");
__asm("lea ecx, [eax+0x0C]\n"); //friendid offset
__asm("mov ecx, [ecx]\n");
__asm("cmp ecx, 0x00746C75\n"); //ult
__asm("jne skip_remove_login\n");
//fake login detected, cleanup
__asm("mov dword ptr [ebx], 0x00000000\n");
__asm("skip_remove_login:\n");
__asm("pop ecx\n");
__asm("pop ebx\n");
real_remove_fake_login();
}
static bool patch_favorite_categ(const char *game_dll_fn) {
DWORD dllSize = 0;
@ -695,6 +747,19 @@ static bool patch_favorite_categ(const char *game_dll_fn) {
g_playerdata_ptr_addr = (*(uint32_t *)(data + pattern_offset + 0x25));
}
//and I need to remove the fake "logged in" status on credit end to prevent a crash
{
int64_t pattern_offset = search(data, dllSize, "\x84\xC0\x74\x07\xBB\x01\x00\x00\x00\xEB\x02\x33\xDB", 13, 0);
if (pattern_offset == -1) {
LOG("popnhax: local_favorites: cannot find end of credit check if logged function\n");
return false;
}
uint64_t patch_addr = (int64_t)data + pattern_offset - 0x05;
MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_remove_fake_login,
(void **)&real_remove_fake_login);
}
//hook result screen to replace 3 functions
{
@ -745,7 +810,7 @@ static bool patch_favorite_categ(const char *game_dll_fn) {
return true;
}
static bool patch_custom_categ(const char *game_dll_fn) {
static bool patch_custom_categ(const char *game_dll_fn, uint16_t min_id) {
DWORD dllSize = 0;
char *data = getDllData(game_dll_fn, &dllSize);
@ -890,68 +955,21 @@ static bool patch_custom_categ(const char *game_dll_fn) {
char formatted_title[128];
sprintf(formatted_title, g_categformat, g_categname);
LOG("popnhax: custom %s \"%s\" injected (for songids ", g_subcategmode? "subcategories":"category", formatted_title);
if (g_max_id)
LOG("between %d and %d (incl.))\n", g_min_id, g_max_id);
else
LOG("%d and up)\n", g_min_id);
LOG("popnhax: custom %s \"%s\" injected", g_subcategmode? "subcategories":"category", formatted_title);
if (min_id)
LOG(" (for songids >= %d)", min_id);
LOG("\n");
return true;
}
//extract folder name (cut "data_mods")
static char *get_folder_name(const char* path) {
size_t len = (size_t)(strchr(path+10, '\\')-(path+10));
char *categ_name = (char*) malloc(len+1);
strncpy(categ_name, path+10, len);
categ_name[len] = '\0';
return categ_name;
}
static void parse_musicdb(const char *input_filename) {
char *title = get_folder_name(input_filename);
subcategory_s *subcateg = get_subcateg(title);
if ( subcateg == NULL )
{
subcategories = (subcategory_s*)realloc(subcategories, sizeof(subcategory_s)*((++g_subcateg_count)+1));
subcateg = &(subcategories[g_subcateg_count]);
subcateg->name = strdup(title);
subcateg->songlist = NULL;
subcateg->size = 0;
}
property* musicdb = load_prop_file(input_filename);
//iterate over all music id
property_node *prop = NULL;
if ((prop = property_search(musicdb, NULL, "/database/music"))) {
for (; prop != NULL; prop = property_node_traversal(prop, TRAVERSE_NEXT_SEARCH_RESULT)) {
char idxStr[256] = {};
property_node_refer(musicdb, prop, "id@", PROPERTY_TYPE_ATTR, idxStr,
sizeof(idxStr));
uint32_t songid = atoi(idxStr);
add_song_to_subcateg(songid, subcateg);
}
}
}
static void load_databases() {
SearchFile s;
void init_subcategories() {
g_subcategmode = true;
g_subcateg_count = 0;
subcategories = (subcategory_s*)realloc(subcategories, sizeof(subcategory_s)*(1));
subcategories[0].name = strdup("ALL SONGS");
subcategories[0].songlist = NULL;
subcategories[0].size = 0;
s.search("data_mods", "xml", true);
auto result = s.getResult();
for(uint16_t i=0;i<result.size();i++)
{
if ( strstr(result[i].c_str(), "musicdb") == NULL )
continue;
parse_musicdb(result[i].c_str());
}
}
static void print_databases() {
@ -968,12 +986,18 @@ void hook_after_getlevel()
{
__asm("push ebx\n");
__asm("mov ebx, dword ptr [esp+0x04]\n");
__asm("cmp ebx, _g_min_id\n");
__asm("jb real_level\n");
__asm("cmp dword ptr _g_max_id, 0\n");
__asm("je force_level_0\n");
__asm("cmp ebx, _g_max_id\n");
__asm("ja real_level\n");
__asm("push eax\n");
__asm("push ecx\n");
__asm("push edx\n");
__asm("push ebx\n");
__asm("call %P0" : : "i"(is_excluded_from_level));
__asm("test eax, eax\n");
__asm("pop ebx\n");
__asm("pop edx\n");
__asm("pop ecx\n");
__asm("pop eax\n");
__asm("jz real_level\n");
__asm("force_level_0:\n");
__asm("mov eax, 0x00\n");
@ -1008,8 +1032,6 @@ bool patch_exclude(const char *game_dll_fn)
bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config)
{
g_min_id = config->custom_categ_min_songid;
g_max_id = config->custom_categ_max_songid;
uint8_t mode = config->custom_categ;
char icon_path[64];
@ -1024,11 +1046,8 @@ bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config)
g_categicon = "cate_13";
}
if (mode == 2)
if (mode == 1)
{
g_subcategmode = true;
load_databases();
} else {
songlist = (uint32_t*)calloc(1,5); //for some reason it crashes without that 4 cells extra margin
}
@ -1041,7 +1060,7 @@ bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config)
else
g_categformat = "%s";
if (!patch_custom_categ(dllFilename))
if (!patch_custom_categ(dllFilename, config->custom_categ_min_songid))
return false;
if (mode == 2)
@ -1059,8 +1078,12 @@ bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config)
if (config->custom_exclude_from_version)
LOG("popnhax: Customs excluded from version folders\n"); //musichax_core_init took care of it
if (config->custom_exclude_from_level)
{
g_exclude_omni = config->exclude_omni;
patch_exclude(dllFilename);
}
return true;
}

View File

@ -3,6 +3,20 @@
#include <stdint.h>
#include "popnhax/config.h"
#include "util/bst.h"
typedef struct {
char *name;
uint32_t size;
uint32_t *songlist; //really is a (songlist_t *) pointer
} subcategory_s;
extern uint32_t g_max_id;
extern bst_t *g_customs_bst;
void init_subcategories();
void add_song_to_subcateg(uint32_t songid, subcategory_s* subcateg);
subcategory_s* get_subcateg(const char *title);
bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config);
bool patch_local_favorites(const char *dllFilename, uint8_t version);

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,11 @@
#include <windows.h>
#include "imports/avs.h"
#include "util/bst.h"
#include "util/patch.h"
#include "util/log.h"
#include "xmlhelper.h"
#include "custom_categs.h"
#include "tableinfo.h"
#include "loader.h"
@ -819,12 +821,76 @@ void parse_charadb(const char *input_filename, const char *target) {
free(config_xml);
}
static char *get_subcateg_title(const char* path) {
char *categ_name = NULL;
char filename[64];
//try to open "folderpath/_name.txt"
size_t len = (size_t)(strchr(path+10, '\\')-(path));
strncpy(filename, path, len);
sprintf(filename+len, "\\_name.txt");
FILE *file = fopen(filename, "r");
if ( file != NULL ) {
//if it has a custom title, use it
char line[64];
if (fgets(line, sizeof(line), file)) {
//handle UTF-8 BOM since that could be common
categ_name = (memcmp(line, "\xEF\xBB\xBF", 3) == 0) ? strdup(line+3) : strdup(line);
LOG("%s sets subcategory name to %s\n", filename, categ_name);
}
fclose(file);
} else { // or just keep folder name by itself (cut "data_mods")
len = (size_t)(strchr(path+10, '\\')-(path+10));
categ_name = (char*) malloc(len+1);
strncpy(categ_name, path+10, len);
categ_name[len] = '\0';
}
return categ_name;
}
#define F_OK 0
static bool is_excluded_folder(const char *path)
{
char filename[64];
//try to open "folderpath/_exclude"
size_t len = (size_t)(strchr(path+10, '\\')-(path));
strncpy(filename, path, len);
sprintf(filename+len, "\\_exclude");
if (access(filename, F_OK) == 0)
{
LOG("%s causes folder to be excluded from customs (contents will be treated as regular songs)\n", filename);
return true;
}
if ( path[strlen("data_mods/")] == '_' )
{
filename[strchr(path+10, '\\')-path] = '\0';
LOG("%s starting with _ causes folder to be excluded from customs (contents will be treated as regular songs)\n", filename);
return true;
}
return false;
}
void parse_musicdb(const char *input_filename, const char *target, struct popnhax_config *config) {
if (!file_exists(input_filename)) {
printf("Couldn't find %s, skipping...\n", input_filename);
return;
}
bool excluded = (config->custom_categ && is_excluded_folder(input_filename));
char *subcateg_title = NULL;
subcategory_s *subcateg = NULL;
if (config->custom_categ == 2 && !excluded)
{
subcateg_title = get_subcateg_title(input_filename);
subcateg = get_subcateg(subcateg_title); //will return a new one if not found
}
property *config_xml = load_prop_file(input_filename);
if (target && strlen(target) > 0) {
@ -860,7 +926,22 @@ void parse_musicdb(const char *input_filename, const char *target, struct popnha
// If it doesn't exist, create a new entry in memory
// Update the data in-place and make all parameters optional
music_entry *m = get_music(idx);
bool is_fresh = m == NULL;
bool is_fresh = m == NULL; // ie. not part of internal songdb
bool is_gone = ( m != NULL && strcmp((const char*) m->title_ptr, "\x81\x5D") == 0); // removed entries all have this title (SJIS "-")
// Update customs/omni songid list
if ( is_fresh || is_gone || config->partial_entries )
{
if ( idx >= config->custom_categ_min_songid && !excluded && bst_search(g_customs_bst, idx) == NULL )
{
g_customs_bst = bst_insert(g_customs_bst, idx);
//LOG("%d inserted into customs bst\n", idx);
if (config->custom_categ == 2)
{
add_song_to_subcateg(idx, subcateg);
}
}
}
if (is_fresh) {
// Default music entry
@ -916,13 +997,11 @@ void parse_musicdb(const char *input_filename, const char *target, struct popnha
}
}
//force loading background for unilab
//m->mask |= 0x100;
if ( config->custom_categ
&& config->custom_exclude_from_version
&& idx >= config->custom_categ_min_songid
&& (config->custom_categ_max_songid == 0 || idx <= config->custom_categ_max_songid) )
&& !excluded
&& idx >= config->custom_categ_min_songid
&& ( is_fresh || config->exclude_omni ) )
{
m->cs_version = 0;
m->folder = 0;
@ -1003,6 +1082,11 @@ void parse_musicdb(const char *input_filename, const char *target, struct popnha
}
free(config_xml);
if (config->custom_categ == 2 && !excluded)
{
free(subcateg_title);
}
}
void load_databases(const char *target_datecode, struct popnhax_config *config) {
@ -1021,6 +1105,9 @@ void load_databases(const char *target_datecode, struct popnhax_config *config)
parse_charadb(result[i].c_str(), target_datecode);
}
if (config->custom_categ == 2)
init_subcategories();
for(uint16_t i=0;i<result.size();i++)
{
if ( strstr(result[i].c_str(), "musicdb") == NULL )

View File

@ -2,6 +2,7 @@ libs += util
srcpp_util := \
fuzzy_search.cc \
bst.cc \
search.cc \
cmdline.cc \
patch.cc \

34
util/bst.cc Normal file
View File

@ -0,0 +1,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "bst.h"
bst_t* bst_search(bst_t *root, uint32_t val)
{
if( root == NULL || root->data == val )
return root;
else if( val > (root->data) )
return bst_search(root->right, val);
else
return bst_search(root->left,val);
}
bst_t* bst_insert(bst_t *root, uint32_t val)
{
if ( root == NULL )
{
bst_t *p;
p = (bst_t *)malloc(sizeof(bst_t));
p->data = val;
p->left = NULL;
p->right = NULL;
return p;
}
else if ( val > root->data )
root->right = bst_insert(root->right, val);
else
root->left = bst_insert(root->left, val);
return root;
}

14
util/bst.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __BST_H__
#define __BST_H__
typedef struct bst_s
{
uint32_t data;
struct bst_s *right;
struct bst_s *left;
} bst_t;
bst_t* bst_search(bst_t *root, uint32_t val);
bst_t* bst_insert(bst_t *root, uint32_t val);
#endif