diff --git a/app/src/main/cpp/GakumasLocalify/Hook.cpp b/app/src/main/cpp/GakumasLocalify/Hook.cpp index 9fd86d5..068e7aa 100644 --- a/app/src/main/cpp/GakumasLocalify/Hook.cpp +++ b/app/src/main/cpp/GakumasLocalify/Hook.cpp @@ -433,6 +433,48 @@ namespace GakumasLocal::HookMain { return VLDOF_IsActive_Orig(_this); } + DEFINE_HOOK(void, CampusQualityManager_set_TargetFrameRate, (void* _this, float value)) { + // Log::InfoFmt("CampusQualityManager_set_TargetFrameRate: %f", value); + const auto configFps = Config::targetFrameRate; + CampusQualityManager_set_TargetFrameRate_Orig(_this, configFps == 0 ? value : (float)configFps); + } + + DEFINE_HOOK(void, CampusQualityManager_ApplySetting, (void* _this, int qualitySettingsLevel, int maxBufferPixel, float renderScale, int volumeIndex)) { + if (Config::targetFrameRate != 0) { + CampusQualityManager_set_TargetFrameRate_Orig(_this, Config::targetFrameRate); + } + if (Config::useCustomeGraphicSettings) { + static auto SetReflectionQuality = Il2cppUtils::GetMethod("campus-submodule.Runtime.dll", "Campus.Common", + "CampusQualityManager", "SetReflectionQuality"); + static auto SetLODQuality = Il2cppUtils::GetMethod("campus-submodule.Runtime.dll", "Campus.Common", + "CampusQualityManager", "SetLODQuality"); + + static auto Enum_GetValues = Il2cppUtils::GetMethod("mscorlib.dll", "System", "Enum", "GetValues"); + + static auto QualityLevel_klass = Il2cppUtils::GetClass("campus-submodule.Runtime.dll", "", "QualityLevel"); + + static auto values = Enum_GetValues->Invoke*>(QualityLevel_klass->GetType())->ToVector(); + if (values.empty()) { + values = {0x0, 0xa, 0x14, 0x1e, 0x28, 0x64}; + } + if (Config::lodQualityLevel >= values.size()) Config::lodQualityLevel = values.size() - 1; + if (Config::reflectionQualityLevel >= values.size()) Config::reflectionQualityLevel = values.size() - 1; + + SetLODQuality->Invoke(_this, values[Config::lodQualityLevel]); + SetReflectionQuality->Invoke(_this, values[Config::reflectionQualityLevel]); + + qualitySettingsLevel = Config::qualitySettingsLevel; + maxBufferPixel = Config::maxBufferPixel; + renderScale = Config::renderScale; + volumeIndex = Config::volumeIndex; + + Log::ShowToastFmt("ApplySetting\nqualityLevel: %d, maxBufferPixel: %d\nenderScale: %f, volumeIndex: %d\nLODQualityLv: %d, ReflectionLv: %d", + qualitySettingsLevel, maxBufferPixel, renderScale, volumeIndex, Config::lodQualityLevel, Config::reflectionQualityLevel); + } + + CampusQualityManager_ApplySetting_Orig(_this, qualitySettingsLevel, maxBufferPixel, renderScale, volumeIndex); + } + void StartInjectFunctions() { const auto hookInstaller = Plugin::GetInstance().GetHookInstaller(); UnityResolve::Init(xdl_open(hookInstaller->m_il2cppLibraryPath.c_str(), RTLD_NOW), UnityResolve::Mode::Il2Cpp); @@ -488,6 +530,14 @@ namespace GakumasLocal::HookMain { Il2cppUtils::GetMethodPointer("Unity.RenderPipelines.Universal.Runtime.dll", "VL.Rendering", "VLDOF", "IsActive")); + ADD_HOOK(CampusQualityManager_ApplySetting, + Il2cppUtils::GetMethodPointer("campus-submodule.Runtime.dll", "Campus.Common", + "CampusQualityManager", "ApplySetting")); + + ADD_HOOK(CampusQualityManager_set_TargetFrameRate, + Il2cppUtils::GetMethodPointer("campus-submodule.Runtime.dll", "Campus.Common", + "CampusQualityManager", "set_TargetFrameRate")); + ADD_HOOK(Internal_LogException, Il2cppUtils::il2cpp_resolve_icall( "UnityEngine.DebugLogHandler::Internal_LogException(System.Exception,UnityEngine.Object)")); ADD_HOOK(Internal_Log, Il2cppUtils::il2cpp_resolve_icall( diff --git a/app/src/main/cpp/GakumasLocalify/Log.cpp b/app/src/main/cpp/GakumasLocalify/Log.cpp index d052a50..80d20ab 100644 --- a/app/src/main/cpp/GakumasLocalify/Log.cpp +++ b/app/src/main/cpp/GakumasLocalify/Log.cpp @@ -1,30 +1,26 @@ #include "Log.h" #include +#include #include #include +#include -std::string format(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - va_list args_copy; - va_copy(args_copy, args); +extern JavaVM* g_javaVM; +extern jclass g_gakumasHookMainClass; +extern jmethodID showToastMethodId; - // 计算格式化后的字符串长度 - int size = vsnprintf(nullptr, 0, fmt, args_copy) + 1; // 加上额外的终止符空间 - va_end(args_copy); - - // 动态分配缓冲区 - char* buffer = new char[size]; - - // 格式化字符串 - vsnprintf(buffer, size, fmt, args); - - va_end(args); - - std::string result(buffer); - delete[] buffer; // 释放缓冲区 - return result; -} +#define GetParamStringResult(name)\ + va_list args;\ + va_start(args, fmt);\ + va_list args_copy;\ + va_copy(args_copy, args);\ + int size = vsnprintf(nullptr, 0, fmt, args_copy) + 1;\ + va_end(args_copy);\ + char* buffer = new char[size];\ + vsnprintf(buffer, size, fmt, args);\ + va_end(args);\ + std::string name(buffer);\ + delete[] buffer namespace GakumasLocal::Log { @@ -33,26 +29,7 @@ namespace GakumasLocal::Log { } void LogFmt(int prio, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - va_list args_copy; - va_copy(args_copy, args); - - // 计算格式化后的字符串长度 - int size = vsnprintf(nullptr, 0, fmt, args_copy) + 1; // 加上额外的终止符空间 - va_end(args_copy); - - // 动态分配缓冲区 - char* buffer = new char[size]; - - // 格式化字符串 - vsnprintf(buffer, size, fmt, args); - - va_end(args); - - std::string result(buffer); - delete[] buffer; // 释放缓冲区 - + GetParamStringResult(result); Log(prio, result.c_str()); } @@ -61,26 +38,7 @@ namespace GakumasLocal::Log { } void InfoFmt(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - va_list args_copy; - va_copy(args_copy, args); - - // 计算格式化后的字符串长度 - int size = vsnprintf(nullptr, 0, fmt, args_copy) + 1; // 加上额外的终止符空间 - va_end(args_copy); - - // 动态分配缓冲区 - char* buffer = new char[size]; - - // 格式化字符串 - vsnprintf(buffer, size, fmt, args); - - va_end(args); - - std::string result(buffer); - delete[] buffer; // 释放缓冲区 - + GetParamStringResult(result); Info(result.c_str()); } @@ -89,26 +47,7 @@ namespace GakumasLocal::Log { } void ErrorFmt(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - va_list args_copy; - va_copy(args_copy, args); - - // 计算格式化后的字符串长度 - int size = vsnprintf(nullptr, 0, fmt, args_copy) + 1; // 加上额外的终止符空间 - va_end(args_copy); - - // 动态分配缓冲区 - char* buffer = new char[size]; - - // 格式化字符串 - vsnprintf(buffer, size, fmt, args); - - va_end(args); - - std::string result(buffer); - delete[] buffer; // 释放缓冲区 - + GetParamStringResult(result); Error(result.c_str()); } @@ -117,50 +56,44 @@ namespace GakumasLocal::Log { } void DebugFmt(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - va_list args_copy; - va_copy(args_copy, args); - - // 计算格式化后的字符串长度 - int size = vsnprintf(nullptr, 0, fmt, args_copy) + 1; // 加上额外的终止符空间 - va_end(args_copy); - - // 动态分配缓冲区 - char* buffer = new char[size]; - - // 格式化字符串 - vsnprintf(buffer, size, fmt, args); - - va_end(args); - - std::string result(buffer); - delete[] buffer; // 释放缓冲区 - + GetParamStringResult(result); Debug(result.c_str()); } void LogUnityLog(int prio, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - va_list args_copy; - va_copy(args_copy, args); - - // 计算格式化后的字符串长度 - int size = vsnprintf(nullptr, 0, fmt, args_copy) + 1; // 加上额外的终止符空间 - va_end(args_copy); - - // 动态分配缓冲区 - char* buffer = new char[size]; - - // 格式化字符串 - vsnprintf(buffer, size, fmt, args); - - va_end(args); - - std::string result(buffer); - delete[] buffer; // 释放缓冲区 - + GetParamStringResult(result); __android_log_write(prio, "GakumasLog", result.c_str()); } + + void ShowToast(const std::string& text) { + DebugFmt("Toast: %s", text.c_str()); + + std::thread([text](){ + auto env = Misc::GetJNIEnv(); + if (!env) { + return; + } + g_javaVM->AttachCurrentThread(&env, nullptr); + + jclass& kotlinClass = g_gakumasHookMainClass; + if (!kotlinClass) { + g_javaVM->DetachCurrentThread(); + return; + } + jmethodID& methodId = showToastMethodId; + if (!methodId) { + g_javaVM->DetachCurrentThread(); + return; + } + jstring param = env->NewStringUTF(text.c_str()); + env->CallStaticVoidMethod(kotlinClass, methodId, param); + + g_javaVM->DetachCurrentThread(); + }).detach(); + } + + void ShowToastFmt(const char* fmt, ...) { + GetParamStringResult(result); + ShowToast(result); + } } diff --git a/app/src/main/cpp/GakumasLocalify/Log.h b/app/src/main/cpp/GakumasLocalify/Log.h index 83f9f02..d411ebe 100644 --- a/app/src/main/cpp/GakumasLocalify/Log.h +++ b/app/src/main/cpp/GakumasLocalify/Log.h @@ -10,6 +10,9 @@ namespace GakumasLocal::Log { void ErrorFmt(const char* fmt, ...); void Debug(const char* msg); void DebugFmt(const char* fmt, ...); + + void ShowToast(const char* text); + void ShowToastFmt(const char* fmt, ...); } #endif //GAKUMAS_LOCALIFY_LOG_H diff --git a/app/src/main/cpp/GakumasLocalify/Misc.cpp b/app/src/main/cpp/GakumasLocalify/Misc.cpp index 99909bf..1745880 100644 --- a/app/src/main/cpp/GakumasLocalify/Misc.cpp +++ b/app/src/main/cpp/GakumasLocalify/Misc.cpp @@ -2,6 +2,10 @@ #include #include +#include + + +extern JavaVM* g_javaVM; namespace GakumasLocal::Misc { @@ -14,4 +18,17 @@ namespace GakumasLocal::Misc { std::wstring_convert, char16_t> utf16conv; return utf16conv.to_bytes(str.data(), str.data() + str.size()); } + + JNIEnv* GetJNIEnv() { + if (!g_javaVM) return nullptr; + JNIEnv* env = nullptr; + if (g_javaVM->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + int status = g_javaVM->AttachCurrentThread(&env, nullptr); + if (status < 0) { + return nullptr; + } + } + return env; + } + } // namespace UmaPyogin::Misc diff --git a/app/src/main/cpp/GakumasLocalify/Misc.h b/app/src/main/cpp/GakumasLocalify/Misc.h index 073062d..3932d3e 100644 --- a/app/src/main/cpp/GakumasLocalify/Misc.h +++ b/app/src/main/cpp/GakumasLocalify/Misc.h @@ -3,6 +3,7 @@ #include #include +#include namespace GakumasLocal { using OpaqueFunctionPointer = void (*)(); @@ -10,6 +11,7 @@ namespace GakumasLocal { namespace Misc { std::u16string ToUTF16(const std::string_view& str); std::string ToUTF8(const std::u16string_view& str); + JNIEnv* GetJNIEnv(); } } diff --git a/app/src/main/cpp/GakumasLocalify/Plugin.h b/app/src/main/cpp/GakumasLocalify/Plugin.h index bba25f1..d4e986e 100644 --- a/app/src/main/cpp/GakumasLocalify/Plugin.h +++ b/app/src/main/cpp/GakumasLocalify/Plugin.h @@ -4,6 +4,7 @@ #include "Misc.h" #include #include +#include namespace GakumasLocal { struct HookInstaller diff --git a/app/src/main/cpp/GakumasLocalify/config/Config.cpp b/app/src/main/cpp/GakumasLocalify/config/Config.cpp index 4915d36..b2f0c13 100644 --- a/app/src/main/cpp/GakumasLocalify/config/Config.cpp +++ b/app/src/main/cpp/GakumasLocalify/config/Config.cpp @@ -14,6 +14,14 @@ namespace GakumasLocal::Config { std::string liveCustomeHeadId = ""; std::string liveCustomeCostumeId = ""; + bool useCustomeGraphicSettings = false; + float renderScale = 0.77f; + int qualitySettingsLevel = 3; + int volumeIndex = 3; + int maxBufferPixel = 3384; + int reflectionQualityLevel = 4; + int lodQualityLevel = 4; + void LoadConfig(const std::string& configStr) { try { const auto config = nlohmann::json::parse(configStr); @@ -27,6 +35,13 @@ namespace GakumasLocal::Config { GetConfigItem(enableLiveCustomeDress); GetConfigItem(liveCustomeHeadId); GetConfigItem(liveCustomeCostumeId); + GetConfigItem(useCustomeGraphicSettings); + GetConfigItem(renderScale); + GetConfigItem(qualitySettingsLevel); + GetConfigItem(volumeIndex); + GetConfigItem(maxBufferPixel); + GetConfigItem(reflectionQualityLevel); + GetConfigItem(lodQualityLevel); } catch (std::exception& e) { diff --git a/app/src/main/cpp/GakumasLocalify/config/Config.hpp b/app/src/main/cpp/GakumasLocalify/config/Config.hpp index d6c1dea..0de274e 100644 --- a/app/src/main/cpp/GakumasLocalify/config/Config.hpp +++ b/app/src/main/cpp/GakumasLocalify/config/Config.hpp @@ -14,6 +14,15 @@ namespace GakumasLocal::Config { extern std::string liveCustomeHeadId; extern std::string liveCustomeCostumeId; + extern bool useCustomeGraphicSettings; + extern float renderScale; + extern int qualitySettingsLevel; + extern int volumeIndex; + extern int maxBufferPixel; + + extern int reflectionQualityLevel; + extern int lodQualityLevel; + void LoadConfig(const std::string& configStr); } diff --git a/app/src/main/cpp/libMarryKotone.cpp b/app/src/main/cpp/libMarryKotone.cpp index ea13a2b..112fbef 100644 --- a/app/src/main/cpp/libMarryKotone.cpp +++ b/app/src/main/cpp/libMarryKotone.cpp @@ -9,6 +9,10 @@ #include "GakumasLocalify/camera/camera.hpp" #include "GakumasLocalify/config/Config.hpp" +JavaVM* g_javaVM = nullptr; +jclass g_gakumasHookMainClass = nullptr; +jmethodID showToastMethodId = nullptr; + namespace { class AndroidHookInstaller : public GakumasLocal::HookInstaller @@ -40,11 +44,20 @@ namespace }; } +extern "C" +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM* vm, void* reserved) { + g_javaVM = vm; + return JNI_VERSION_1_6; +} extern "C" JNIEXPORT void JNICALL Java_io_github_chinosk_gakumas_localify_GakumasHookMain_initHook(JNIEnv *env, jclass clazz, jstring targetLibraryPath, jstring localizationFilesDir) { + g_gakumasHookMainClass = clazz; + showToastMethodId = env->GetStaticMethodID(clazz, "showToast", "(Ljava/lang/String;)V"); + const auto targetLibraryPathChars = env->GetStringUTFChars(targetLibraryPath, nullptr); const std::string targetLibraryPathStr = targetLibraryPathChars; diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt index 60cc485..fd6b711 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt @@ -22,12 +22,12 @@ import android.widget.Toast import de.robv.android.xposed.XposedBridge import java.io.File +val TAG = "GakumasLocalify" class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { private lateinit var modulePath: String private var nativeLibLoadSuccess: Boolean private var alreadyInitialized = false - private val TAG = "GakumasLocalify" private val targetPackageName = "com.bandainamcoent.idolmaster_gakuen" private val nativeLibName = "MarryKotone" @@ -115,20 +115,6 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { }) } - private fun showToast(message: String) { - val app = AndroidAppHelper.currentApplication() - val context = app?.applicationContext - if (context != null) { - val handler = Handler(Looper.getMainLooper()) - handler.post { - Toast.makeText(context, message, Toast.LENGTH_SHORT).show() - } - } - else { - Log.e(TAG, "showToast: $message failed: applicationContext is null") - } - } - fun initGkmsConfig(activity: Activity) { val intent = activity.intent val gkmsData = intent.getStringExtra("gkmsData") @@ -160,8 +146,22 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { external fun keyboardEvent(keyCode: Int, action: Int) @JvmStatic external fun loadConfig(configJsonStr: String) - } + @JvmStatic + fun showToast(message: String) { + val app = AndroidAppHelper.currentApplication() + val context = app?.applicationContext + if (context != null) { + val handler = Handler(Looper.getMainLooper()) + handler.post { + Toast.makeText(context, message, Toast.LENGTH_SHORT).show() + } + } + else { + Log.e(TAG, "showToast: $message failed: applicationContext is null") + } + } + } init { ShadowHook.init( diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/MainActivity.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/MainActivity.kt index acd1f7d..323dd79 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/MainActivity.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/MainActivity.kt @@ -7,6 +7,9 @@ import android.os.Bundle import android.util.Log import android.widget.Toast import androidx.databinding.DataBindingUtil +import androidx.databinding.ObservableField +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout import com.google.gson.Gson import com.google.gson.JsonSyntaxException import io.github.chinosk.gakumas.localify.databinding.ActivityMainBinding @@ -23,27 +26,33 @@ interface ConfigListener { fun onLiveCustomeDressChanged(value: Boolean) fun onLiveCustomeHeadIdChanged(s: CharSequence, start: Int, before: Int, count: Int) fun onLiveCustomeCostumeIdChanged(s: CharSequence, start: Int, before: Int, count: Int) + fun onUseCustomeGraphicSettingsChanged(value: Boolean) + fun onRenderScaleChanged(s: CharSequence, start: Int, before: Int, count: Int) + fun onQualitySettingsLevelChanged(s: CharSequence, start: Int, before: Int, count: Int) + fun onVolumeIndexChanged(s: CharSequence, start: Int, before: Int, count: Int) + fun onMaxBufferPixelChanged(s: CharSequence, start: Int, before: Int, count: Int) + fun onChangePresetQuality(level: Int) + fun onReflectionQualityLevelChanged(s: CharSequence, start: Int, before: Int, count: Int) + fun onLodQualityLevelChanged(s: CharSequence, start: Int, before: Int, count: Int) } class MainActivity : AppCompatActivity(), ConfigListener { - private lateinit var config: GakumasConfig + private lateinit var binding: ActivityMainBinding private val TAG = "GakumasLocalify" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + binding = DataBindingUtil.setContentView(this, R.layout.activity_main) loadConfig() + binding.listener = this val requestData = intent.getStringExtra("gkmsData") if (requestData != null) { onClickStartGame() finish() } - - val binding = DataBindingUtil.setContentView(this, R.layout.activity_main) - binding.config = config - binding.listener = this } private fun showToast(message: String) { @@ -63,34 +72,33 @@ class MainActivity : AppCompatActivity(), ConfigListener { private fun loadConfig() { val configStr = getConfigContent() - val config = try { + binding.config = try { Gson().fromJson(configStr, GakumasConfig::class.java) } catch (e: JsonSyntaxException) { showToast("配置文件异常,已重置: $e") Gson().fromJson("{}", GakumasConfig::class.java) } - this.config = config saveConfig() } private fun saveConfig() { val configFile = File(filesDir, "gkms-config.json") - configFile.writeText(Gson().toJson(config)) + configFile.writeText(Gson().toJson(binding.config!!)) } override fun onEnabledChanged(value: Boolean) { - config.enabled = value + binding.config!!.enabled = value saveConfig() } override fun onEnableFreeCameraChanged(value: Boolean) { - config.enableFreeCamera = value + binding.config!!.enableFreeCamera = value saveConfig() } override fun onUnlockAllLiveChanged(value: Boolean) { - config.unlockAllLive = value + binding.config!!.unlockAllLive = value saveConfig() } @@ -103,7 +111,7 @@ class MainActivity : AppCompatActivity(), ConfigListener { } else { valueStr.toInt() } - config.targetFrameRate = value + binding.config!!.targetFrameRate = value saveConfig() } catch (e: Exception) { @@ -112,17 +120,62 @@ class MainActivity : AppCompatActivity(), ConfigListener { } override fun onLiveCustomeDressChanged(value: Boolean) { - config.enableLiveCustomeDress = value + binding.config!!.enableLiveCustomeDress = value saveConfig() } override fun onLiveCustomeCostumeIdChanged(s: CharSequence, start: Int, before: Int, count: Int) { - config.liveCustomeCostumeId = s.toString() + binding.config!!.liveCustomeCostumeId = s.toString() + saveConfig() + } + + override fun onUseCustomeGraphicSettingsChanged(value: Boolean) { + binding.config!!.useCustomeGraphicSettings = value + saveConfig() + } + + override fun onRenderScaleChanged(s: CharSequence, start: Int, before: Int, count: Int) { + binding.config!!.renderScale = try { + s.toString().toFloat() + } + catch (e: Exception) { + 0.0f + } + saveConfig() + } + + override fun onQualitySettingsLevelChanged(s: CharSequence, start: Int, before: Int, count: Int) { + binding.config!!.qualitySettingsLevel = try { + s.toString().toInt() + } + catch (e: Exception) { + 0 + } + saveConfig() + } + + override fun onVolumeIndexChanged(s: CharSequence, start: Int, before: Int, count: Int) { + binding.config!!.volumeIndex = try { + s.toString().toInt() + } + catch (e: Exception) { + 0 + } + saveConfig() + } + + override fun onMaxBufferPixelChanged(s: CharSequence, start: Int, before: Int, count: Int) { + binding.config!!.maxBufferPixel = try { + s.toString().toInt() + } + catch (e: Exception) { + 0 + } saveConfig() } override fun onLiveCustomeHeadIdChanged(s: CharSequence, start: Int, before: Int, count: Int) { - config.liveCustomeHeadId = s.toString() + binding.config!!.liveCustomeHeadId = s.toString() saveConfig() } @@ -134,4 +187,78 @@ class MainActivity : AppCompatActivity(), ConfigListener { } startActivity(intent) } + + override fun onReflectionQualityLevelChanged(s: CharSequence, start: Int, before: Int, count: Int) { + binding.config!!.reflectionQualityLevel = try { + val value = s.toString().toInt() + if (value > 5) 5 else value + } + catch (e: Exception) { + 0 + } + saveConfig() + } + + override fun onLodQualityLevelChanged(s: CharSequence, start: Int, before: Int, count: Int) { + binding.config!!.lodQualityLevel = try { + val value = s.toString().toInt() + if (value > 5) 5 else value + } + catch (e: Exception) { + 0 + } + saveConfig() + } + + override fun onChangePresetQuality(level: Int) { + when (level) { + 0 -> { + binding.config!!.renderScale = 0.5f + binding.config!!.qualitySettingsLevel = 1 + binding.config!!.volumeIndex = 0 + binding.config!!.maxBufferPixel = 1024 + binding.config!!.lodQualityLevel = 1 + binding.config!!.reflectionQualityLevel = 1 + } + 1 -> { + binding.config!!.renderScale = 0.59f + binding.config!!.qualitySettingsLevel = 1 + binding.config!!.volumeIndex = 1 + binding.config!!.maxBufferPixel = 1440 + binding.config!!.lodQualityLevel = 2 + binding.config!!.reflectionQualityLevel = 2 + } + 2 -> { + binding.config!!.renderScale = 0.67f + binding.config!!.qualitySettingsLevel = 2 + binding.config!!.volumeIndex = 2 + binding.config!!.maxBufferPixel = 2538 + binding.config!!.lodQualityLevel = 3 + binding.config!!.reflectionQualityLevel = 3 + } + 3 -> { + binding.config!!.renderScale = 0.77f + binding.config!!.qualitySettingsLevel = 3 + binding.config!!.volumeIndex = 3 + binding.config!!.maxBufferPixel = 3384 + binding.config!!.lodQualityLevel = 4 + binding.config!!.reflectionQualityLevel = 4 + } + 4 -> { + binding.config!!.renderScale = 1.0f + binding.config!!.qualitySettingsLevel = 5 + binding.config!!.volumeIndex = 4 + binding.config!!.maxBufferPixel = 8190 + binding.config!!.lodQualityLevel = 5 + binding.config!!.reflectionQualityLevel = 5 + } + } + binding.config = binding.config + binding.notifyChange() + saveConfig() + } + + private fun showTextInputLayoutHint(view: TextInputLayout) { + showToast(view.hint.toString()) + } } \ No newline at end of file diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt index 55b7ca6..9f2ab3f 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/models/GakumasConfig.kt @@ -1,12 +1,21 @@ package io.github.chinosk.gakumas.localify.models -data class GakumasConfig( +import androidx.databinding.BaseObservable + +data class GakumasConfig ( var enabled: Boolean = true, var enableFreeCamera: Boolean = false, var targetFrameRate: Int = 0, var unlockAllLive: Boolean = false, var enableLiveCustomeDress: Boolean = false, var liveCustomeHeadId: String = "", - var liveCustomeCostumeId: String = "" -) + var liveCustomeCostumeId: String = "", + var useCustomeGraphicSettings: Boolean = false, + var renderScale: Float = 0.77f, + var qualitySettingsLevel: Int = 3, + var volumeIndex: Int = 3, + var maxBufferPixel: Int = 3384, + var reflectionQualityLevel: Int = 4, // 0~5 + var lodQualityLevel: Int = 4, // 0~5 +) diff --git a/app/src/main/res/drawable/table_row_border.xml b/app/src/main/res/drawable/table_row_border.xml new file mode 100644 index 0000000..4d89eaa --- /dev/null +++ b/app/src/main/res/drawable/table_row_border.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 63e08da..2069330 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -16,174 +16,477 @@ android:padding="6sp" tools:context=".MainActivity"> - - - - - - + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - + android:layout_height="wrap_content" + android:text="@string/gakumas_localify" + android:textColor="@color/black" + android:textSize="20sp" /> - - - - + android:layout_height="25sp" /> - + + + android:layout_height="match_parent"> - + android:checked="@={config.enabled}" + android:onCheckedChanged="@{(view, value) -> listener.onEnabledChanged(value)}" + android:text="@string/enable_plugin" /> + - - - - - - - - + android:layout_height="match_parent"> - - - - - - - - - - - - - - - + android:layout_height="48dp" + android:background="@android:color/transparent" + android:hint="@string/setFpsTitle" + app:boxBackgroundColor="@android:color/transparent"> - - + - - + + + + + android:layout_height="match_parent"> - - - + android:layout_height="48dp" + android:checked="@={config.enableFreeCamera}" + android:onCheckedChanged="@{(view, value) -> listener.onEnableFreeCameraChanged(value)}" + android:text="@string/enable_free_camera" /> + - - - - - + android:layout_height="match_parent"> - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 12d3458..093b278 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,4 +9,6 @@ Live 使用自定义角色 Live 自定义头部 ID (例: costume_head_hski-cstm-0002) Live 自定义服装 ID (例: hski-cstm-0002) + 使用自定义画质设置 + RenderScale (0.5/0.59/0.67/0.77/1.0) \ No newline at end of file