Skip to content

Commit

Permalink
Show DialogAnnounceEvent on click of story event announcement voice
Browse files Browse the repository at this point in the history
  • Loading branch information
Kimjio committed Mar 24, 2023
1 parent 5960204 commit 4929938
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 11 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# umamusume-localify
## Uma Musume: Pretty Derby localify patch


[한국어](README.ko-KR.md)
[中国人](README.zh-Hans.md)

Expand All @@ -25,6 +26,9 @@
### Known issue
- None

# Build
Platform Toolset: clang required

# Resources
- `static.json` upgrade tool - https://github.com/AirJerryWhite/i18upgrade

Expand Down
12 changes: 6 additions & 6 deletions src/VERSIONINFO.rc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,17,1,0
PRODUCTVERSION 1,17,1,0
FILEVERSION 1,18,0,0
PRODUCTVERSION 1,18,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -25,19 +25,19 @@ BEGIN
BEGIN
VALUE "LegalCopyright", "Copyright © Ji O Kim\0"
VALUE "FileDescription", "우마무스메 현지화 패치\0"
VALUE "FileVersion", "1.17.1.0\0"
VALUE "FileVersion", "1.18.0.0\0"
VALUE "InternalName", "umamusume-localify\0"
VALUE "ProductName", "Umamusume Localify\0"
VALUE "ProductVersion", "1.17.1\0"
VALUE "ProductVersion", "1.18.0\0"
END
BLOCK "000004b0"
BEGIN
VALUE "LegalCopyright", "Copyright © Ji O Kim\0"
VALUE "FileDescription", "Localization patch for Umamusume\0"
VALUE "FileVersion", "1.17.1.0\0"
VALUE "FileVersion", "1.18.0.0\0"
VALUE "InternalName", "umamusume-localify\0"
VALUE "ProductName", "Umamusume Localify\0"
VALUE "ProductVersion", "1.17.1\0"
VALUE "ProductVersion", "1.18.0\0"
END
END
BLOCK "VarFileInfo"
Expand Down
226 changes: 224 additions & 2 deletions src/hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,119 @@ namespace
return il2cpp_type_get_object(il2cpp_class_get_type(il2cpp_symbols::get_class(assemblyName, namespaze, klassName)));
}

template<typename... T>
Il2CppDelegate* CreateDelegate(Il2CppObject* target, void (*fn)(Il2CppObject*, T...))
{
auto delegate = reinterpret_cast<MulticastDelegate*>(
il2cpp_object_new(il2cpp_symbols::get_class("mscorlib.dll", "System", "MulticastDelegate")));
delegate->delegates = il2cpp_array_new(il2cpp_symbols::get_class("mscorlib.dll", "System", "Delegate"), 1);
il2cpp_array_setref(delegate->delegates, 0, delegate);
delegate->method_ptr = reinterpret_cast<Il2CppMethodPointer>(fn);

auto methodInfo = reinterpret_cast<MethodInfo*>(il2cpp_object_new(
il2cpp_symbols::get_class("mscorlib.dll", "System.Reflection", "MethodInfo")));
methodInfo->methodPointer = reinterpret_cast<uintptr_t>(delegate->method_ptr);
methodInfo->klass = il2cpp_symbols::get_class("mscorlib.dll", "System.Reflection", "MethodInfo");
delegate->method = methodInfo;
delegate->target = target;
return delegate;
}

template<typename... T>
Il2CppDelegate* CreateUnityAction(Il2CppObject* target, void (*fn)(Il2CppObject*, T...))
{
auto delegate = reinterpret_cast<MulticastDelegate*>(
il2cpp_object_new(il2cpp_symbols::get_class("UnityEngine.CoreModule.dll", "UnityEngine.Events", "UnityAction")));
delegate->delegates = il2cpp_array_new(il2cpp_symbols::get_class("mscorlib.dll", "System", "Delegate"), 1);
il2cpp_array_setref(delegate->delegates, 0, delegate);
delegate->method_ptr = reinterpret_cast<Il2CppMethodPointer>(fn);

auto methodInfo = reinterpret_cast<MethodInfo*>(il2cpp_object_new(
il2cpp_symbols::get_class("mscorlib.dll", "System.Reflection", "MethodInfo")));
methodInfo->methodPointer = reinterpret_cast<uintptr_t>(delegate->method_ptr);
methodInfo->klass = il2cpp_symbols::get_class("mscorlib.dll", "System.Reflection", "MethodInfo");
delegate->method = methodInfo;
delegate->target = target;
return delegate;
}

Il2CppDelegate* GetButtonCommonOnClickDelegate(Il2CppObject* object)
{
if (!object)
{
return nullptr;
}
if (object->klass != il2cpp_symbols::get_class("umamusume.dll", "Gallop", "ButtonCommon"))
{
return nullptr;
}
auto onClickField = il2cpp_class_get_field_from_name(object->klass, "m_OnClick");
Il2CppObject* onClick;
il2cpp_field_get_value(object, onClickField, &onClick);
if (onClick)
{
auto callsField = il2cpp_class_get_field_from_name(onClick->klass, "m_Calls");
Il2CppObject* calls;
il2cpp_field_get_value(onClick, callsField, &calls);
if (calls)
{
auto runtimeCallsField = il2cpp_class_get_field_from_name(calls->klass,
"m_RuntimeCalls");
Il2CppObject* runtimeCalls;
il2cpp_field_get_value(calls, runtimeCallsField, &runtimeCalls);

if (runtimeCalls)
{
FieldInfo* itemsField = il2cpp_class_get_field_from_name(runtimeCalls->klass,
"_items");
Il2CppArraySize* arr;
il2cpp_field_get_value(runtimeCalls, itemsField, &arr);
if (arr)
{
for (int i = 0; i < arr->max_length; i++)
{
auto value = reinterpret_cast<Il2CppObject*>(arr->vector[i]);
if (value)
{
auto delegateField = il2cpp_class_get_field_from_name(value->klass,
"Delegate");
Il2CppDelegate* delegate;
il2cpp_field_get_value(value, delegateField, &delegate);
if (delegate)
{
// Unbox delegate
auto callbackField = il2cpp_class_get_field_from_name(
delegate->target->klass, "callback");
Il2CppDelegate* callback;
il2cpp_field_get_value(delegate->target, callbackField, &callback);

return callback;
}
}
}
}
}
}
}
return nullptr;
}

Il2CppObject* GetSingletonInstance(Il2CppClass* klass)
{
if (!klass || !klass->parent)
{
return nullptr;
}
if (string(klass->parent->name).find("Singleton`1") == string::npos)
{
return nullptr;
}
auto instanceField = il2cpp_class_get_field_from_name(klass, "_instance");
Il2CppObject* instance;
il2cpp_field_static_get_value(instanceField, &instance);
return instance;
}

Boolean GetBoolean(bool value)
{
return reinterpret_cast<Boolean(*)(Il2CppString * value)>(il2cpp_symbols::get_method_pointer(
Expand Down Expand Up @@ -2589,6 +2702,110 @@ namespace
return reinterpret_cast<decltype(CriMana_Player_SetFile_hook)*>(CriMana_Player_SetFile_orig)(_this, binder, moviePath, setMode);
}

void* PartsEpisodeList_SetupStoryExtraEpisodeList_orig = nullptr;

void PartsEpisodeList_SetupStoryExtraEpisodeList_hook(Il2CppObject* _this, Il2CppObject* extraSubCategory, Il2CppObject* partDataList, Il2CppObject* partData, Il2CppDelegate* onClick)
{
reinterpret_cast<decltype(PartsEpisodeList_SetupStoryExtraEpisodeList_hook)*>(PartsEpisodeList_SetupStoryExtraEpisodeList_orig)(_this, extraSubCategory, partDataList, partData, onClick);

int partDataId;

auto partDataIdField = il2cpp_class_get_field_from_name(partData->klass, "<Id>k__BackingField");
il2cpp_field_get_value(partData, partDataIdField, &partDataId);

auto voiceButtonField = il2cpp_class_get_field_from_name(_this->klass, "_voiceButton");
Il2CppObject* voiceButton;
il2cpp_field_get_value(_this, voiceButtonField, &voiceButton);

auto buttonField = il2cpp_class_get_field_from_name(voiceButton->klass, "_playVoiceButton");
Il2CppObject* button;
il2cpp_field_get_value(voiceButton, buttonField, &button);

if (button)
{
auto callback = GetButtonCommonOnClickDelegate(button);
if (callback)
{
auto newFn = *(
[](Il2CppObject* storyIdBox)
{

int storyId = *reinterpret_cast<int*>(il2cpp_object_unbox(storyIdBox));

auto masterDataManager = GetSingletonInstance(
il2cpp_symbols::get_class(
"umamusume.dll", "Gallop",
"MasterDataManager"));
auto masterBannerData = reinterpret_cast<Il2CppObject * (*)(
Il2CppObject*)>(il2cpp_class_get_method_from_name(
masterDataManager->klass,
"get_masterBannerData",
0)->methodPointer)(masterDataManager);

auto bannerList = reinterpret_cast<Il2CppObject * (*)(
Il2CppObject*,
int)>(il2cpp_class_get_method_from_name(
masterBannerData->klass,
"GetListWithGroupId",
1)->methodPointer)(masterBannerData,
7);

FieldInfo* itemsField = il2cpp_class_get_field_from_name(
bannerList->klass, "_items");
Il2CppArraySize* arr;
il2cpp_field_get_value(bannerList, itemsField,
&arr);

int announceId = -1;

for (int i = 0; i < arr->max_length; i++)
{
auto item = reinterpret_cast<Il2CppObject*>(arr->vector[i]);
if (item)
{
auto typeField = il2cpp_class_get_field_from_name(
item->klass, "Type");
int type;
il2cpp_field_get_value(item, typeField,
&type);
auto conditionValueField = il2cpp_class_get_field_from_name(
item->klass, "ConditionValue");
int conditionValue;
il2cpp_field_get_value(item,
conditionValueField,
&conditionValue);
if (type == 7 &&
conditionValue == storyId)
{
auto transitionField = il2cpp_class_get_field_from_name(
item->klass, "Transition");
il2cpp_field_get_value(item,
transitionField,
&announceId);
break;
}
}
}

if (announceId == -1 && storyId < 1005)
{
announceId = storyId - 1002;
}

auto action = CreateDelegate(storyIdBox, *([](Il2CppObject*) {}));

reinterpret_cast<void (*)(int,
Il2CppDelegate*,
Il2CppDelegate*)>(il2cpp_symbols::get_method_pointer(
"umamusume.dll", "Gallop",
"DialogAnnounceEvent", "Open", 3))(announceId, action, action);
});
reinterpret_cast<void (*)(Il2CppObject*, Il2CppDelegate*)>(il2cpp_class_get_method_from_name(button->klass, "SetOnClick", 1)->methodPointer)(button,
CreateUnityAction(il2cpp_value_box(il2cpp_symbols::get_class("mscorlib.dll", "System", "Int32"), &partDataId), newFn));
}
}
}

void adjust_size()
{
thread([]()
Expand Down Expand Up @@ -2628,11 +2845,11 @@ namespace
if (g_static_entries_use_text_id_name)
{
string textIdName = GetTextIdNameById(i);
text_id_static_entries.emplace_back(make_pair(textIdName, str->start_char));
text_id_static_entries.emplace_back(textIdName, str->start_char);
if (local::get_localized_string(textIdName) == nullptr ||
local::wide_u8(local::get_localized_string(textIdName)->start_char) == local::wide_u8(str->start_char))
{
text_id_not_matched_entries.emplace_back(make_pair(textIdName, str->start_char));
text_id_not_matched_entries.emplace_back(textIdName, str->start_char);
}
}
else if (g_static_entries_use_hash)
Expand Down Expand Up @@ -3162,6 +3379,9 @@ namespace
auto MoviePlayerForObj_AdjustScreenSize_addr = il2cpp_symbols::get_method_pointer(
"Cute.Cri.Assembly.dll", "Cute.Cri", "MoviePlayerForObj", "AdjustScreenSize", 2);

auto PartsEpisodeList_SetupStoryExtraEpisodeList_addr = il2cpp_symbols::get_method_pointer(
"umamusume.dll", "Gallop", "PartsEpisodeList", "SetupStoryExtraEpisodeList", 4);

load_from_file = reinterpret_cast<Il2CppObject * (*)(Il2CppString * path)>(il2cpp_symbols::get_method_pointer(
"UnityEngine.AssetBundleModule.dll", "UnityEngine", "AssetBundle",
"LoadFromFile", 1));
Expand Down Expand Up @@ -3285,6 +3505,8 @@ namespace
}
#pragma endregion

ADD_HOOK(PartsEpisodeList_SetupStoryExtraEpisodeList, "Gallop.PartsEpisodeList::SetupStoryExtraEpisodeList at %p\n");

ADD_HOOK(CriMana_Player_SetFile, "CriWare.CriMana.Player::SetFile at %p\n");

ADD_HOOK(GameSystem_FixedUpdate, "Gallop.GameSystem::FixedUpdate at %p\n");
Expand Down
6 changes: 4 additions & 2 deletions src/il2cpp/il2cpp_symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ il2cpp_field_get_parent_t il2cpp_field_get_parent;
il2cpp_field_get_offset_t il2cpp_field_get_offset;
il2cpp_class_get_property_from_name_t il2cpp_class_get_property_from_name;
il2cpp_runtime_object_init_t il2cpp_runtime_object_init;
il2cpp_value_box_t il2cpp_value_box;
il2cpp_object_unbox_t il2cpp_object_unbox;

char* il2cpp_array_addr_with_size(void* array, int32_t size, uintptr_t idx)
{
Expand All @@ -66,8 +68,6 @@ namespace il2cpp_symbols
{
#define RESOLVE_IMPORT(name) name = reinterpret_cast<name##_t>(GetProcAddress(game_module, #name))

void* il2cpp_domain = nullptr;

void init(HMODULE game_module)
{
RESOLVE_IMPORT(il2cpp_string_new_utf16);
Expand Down Expand Up @@ -126,6 +126,8 @@ namespace il2cpp_symbols
RESOLVE_IMPORT(il2cpp_field_get_offset);
RESOLVE_IMPORT(il2cpp_class_get_property_from_name);
RESOLVE_IMPORT(il2cpp_runtime_object_init);
RESOLVE_IMPORT(il2cpp_value_box);
RESOLVE_IMPORT(il2cpp_object_unbox);

il2cpp_domain = il2cpp_domain_get();
}
Expand Down
12 changes: 11 additions & 1 deletion src/il2cpp/il2cpp_symbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,10 @@ typedef struct Il2CppDelegate
bool method_is_virtual;
} Il2CppDelegate;

typedef struct MulticastDelegate : Il2CppDelegate {
Il2CppArraySize* delegates;
} MulticastDelegate;

// function types
typedef Il2CppString* (*il2cpp_string_new_utf16_t)(const wchar_t* str, unsigned int len);
typedef Il2CppString* (*il2cpp_string_new_t)(const char* str);
Expand All @@ -494,7 +498,7 @@ typedef const Il2CppType* (*il2cpp_method_get_param_t)(const MethodInfo* method,
typedef Il2CppObject* (*il2cpp_object_new_t)(Il2CppClass* klass);
typedef void (*il2cpp_add_internal_call_t)(const char* name, uintptr_t pointer);
typedef void* (*il2cpp_resolve_icall_t)(const char* name);
typedef void* (*il2cpp_array_new_t)(Il2CppClass* klass, uintptr_t count);
typedef Il2CppArraySize* (*il2cpp_array_new_t)(Il2CppClass* klass, uintptr_t count);
typedef void* (*il2cpp_thread_attach_t)(void* domain);
typedef void (*il2cpp_thread_detach_t)(void* thread);
typedef const Il2CppType* (*il2cpp_class_get_type_t)(Il2CppClass* klass);
Expand Down Expand Up @@ -536,6 +540,8 @@ typedef Il2CppClass* (*il2cpp_field_get_parent_t)(FieldInfo* field);
typedef size_t (*il2cpp_field_get_offset_t)(FieldInfo* field);
typedef const PropertyInfo* (*il2cpp_class_get_property_from_name_t)(Il2CppClass* klass, const char* name);
typedef void (*il2cpp_runtime_object_init_t)(Il2CppObject* obj);
typedef Il2CppObject* (*il2cpp_value_box_t)(Il2CppClass* klass, void* data);
typedef void* (*il2cpp_object_unbox_t)(Il2CppObject* obj);

// function defines
extern il2cpp_string_new_utf16_t il2cpp_string_new_utf16;
Expand Down Expand Up @@ -594,6 +600,8 @@ extern il2cpp_field_get_parent_t il2cpp_field_get_parent;
extern il2cpp_field_get_offset_t il2cpp_field_get_offset;
extern il2cpp_class_get_property_from_name_t il2cpp_class_get_property_from_name;
extern il2cpp_runtime_object_init_t il2cpp_runtime_object_init;
extern il2cpp_value_box_t il2cpp_value_box;
extern il2cpp_object_unbox_t il2cpp_object_unbox;

char* il2cpp_array_addr_with_size(void* arr, int32_t size, uintptr_t idx);

Expand All @@ -608,6 +616,8 @@ char* il2cpp_array_addr_with_size(void* arr, int32_t size, uintptr_t idx);

namespace il2cpp_symbols
{
inline void* il2cpp_domain = nullptr;

void init(HMODULE game_module);
uintptr_t get_method_pointer(const char* assemblyName, const char* namespaze,
const char* klassName, const char* name, int argsCount);
Expand Down

0 comments on commit 4929938

Please sign in to comment.