commit 905f9f62f2713ee6101f94602cdda25691c4cba7 Author: GP <158521072@qq.com> Date: Wed Aug 13 14:51:35 2025 +0800 first commit diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..5f8ddb8 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,30 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + buildToolsVersion "33.0.0" + + defaultConfig { + applicationId "com.bytecat.algui" + minSdkVersion 24 + targetSdkVersion 28 + versionCode 121 + versionName "1.2.1" + renderscriptTargetApi 23 + renderscriptSupportModeEnabled true + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { +implementation 'androidx.fragment:fragment:1.3.6' + implementation 'androidx.interpolator:interpolator:1.0.0' + implementation fileTree(dir: "libs", include: ["*.jar"]) + +} diff --git a/app/libs/Narcissus.dex b/app/libs/Narcissus.dex new file mode 100644 index 0000000..67fee58 Binary files /dev/null and b/app/libs/Narcissus.dex differ diff --git a/app/libs/Narcissus.jar b/app/libs/Narcissus.jar new file mode 100644 index 0000000..d17e93c Binary files /dev/null and b/app/libs/Narcissus.jar differ diff --git a/app/libs/andronid.jar b/app/libs/andronid.jar new file mode 100644 index 0000000..a8e2155 Binary files /dev/null and b/app/libs/andronid.jar differ diff --git a/app/libs/encrypt.jar b/app/libs/encrypt.jar new file mode 100644 index 0000000..b755755 Binary files /dev/null and b/app/libs/encrypt.jar differ diff --git a/app/libs/fastjson-1.2.9.jar b/app/libs/fastjson-1.2.9.jar new file mode 100644 index 0000000..839cea3 Binary files /dev/null and b/app/libs/fastjson-1.2.9.jar differ diff --git a/app/libs/libsu.jar b/app/libs/libsu.jar new file mode 100644 index 0000000..28f7384 Binary files /dev/null and b/app/libs/libsu.jar differ diff --git a/app/libs/okhttp-3.8.0.jar b/app/libs/okhttp-3.8.0.jar new file mode 100644 index 0000000..5019d2f Binary files /dev/null and b/app/libs/okhttp-3.8.0.jar differ diff --git a/app/libs/okio-1.9.0.jar b/app/libs/okio-1.9.0.jar new file mode 100644 index 0000000..3c42b93 Binary files /dev/null and b/app/libs/okio-1.9.0.jar differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..94d7be2 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/AlguiJRoots.jar b/app/src/main/assets/AlguiJRoots.jar new file mode 100644 index 0000000..46c2dbb Binary files /dev/null and b/app/src/main/assets/AlguiJRoots.jar differ diff --git a/app/src/main/assets/MY.ttf b/app/src/main/assets/MY.ttf new file mode 100644 index 0000000..330c074 Binary files /dev/null and b/app/src/main/assets/MY.ttf differ diff --git a/app/src/main/assets/MY1.ttf b/app/src/main/assets/MY1.ttf new file mode 100644 index 0000000..17b25ac Binary files /dev/null and b/app/src/main/assets/MY1.ttf differ diff --git a/app/src/main/assets/click.ogg b/app/src/main/assets/click.ogg new file mode 100644 index 0000000..9a04af9 Binary files /dev/null and b/app/src/main/assets/click.ogg differ diff --git a/app/src/main/assets/close.mp3 b/app/src/main/assets/close.mp3 new file mode 100644 index 0000000..d10b3d4 Binary files /dev/null and b/app/src/main/assets/close.mp3 differ diff --git a/app/src/main/assets/cont.ogg b/app/src/main/assets/cont.ogg new file mode 100644 index 0000000..06e8be8 Binary files /dev/null and b/app/src/main/assets/cont.ogg differ diff --git a/app/src/main/assets/fonts/TrosCore.ttf b/app/src/main/assets/fonts/TrosCore.ttf new file mode 100644 index 0000000..70eb993 Binary files /dev/null and b/app/src/main/assets/fonts/TrosCore.ttf differ diff --git a/app/src/main/assets/gradient_border.xml b/app/src/main/assets/gradient_border.xml new file mode 100644 index 0000000..065248e --- /dev/null +++ b/app/src/main/assets/gradient_border.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/libalguivv.so b/app/src/main/assets/libalguivv.so new file mode 100644 index 0000000..f277575 Binary files /dev/null and b/app/src/main/assets/libalguivv.so differ diff --git a/app/src/main/assets/libdfw.so b/app/src/main/assets/libdfw.so new file mode 100644 index 0000000..30c2fff Binary files /dev/null and b/app/src/main/assets/libdfw.so differ diff --git a/app/src/main/assets/libxfw.so b/app/src/main/assets/libxfw.so new file mode 100644 index 0000000..43a2d47 Binary files /dev/null and b/app/src/main/assets/libxfw.so differ diff --git a/app/src/main/assets/libzcfw.so b/app/src/main/assets/libzcfw.so new file mode 100644 index 0000000..0332862 Binary files /dev/null and b/app/src/main/assets/libzcfw.so differ diff --git a/app/src/main/assets/oopen.ogg b/app/src/main/assets/oopen.ogg new file mode 100644 index 0000000..e5241ed Binary files /dev/null and b/app/src/main/assets/oopen.ogg differ diff --git a/app/src/main/assets/op.ogg b/app/src/main/assets/op.ogg new file mode 100644 index 0000000..87163b0 Binary files /dev/null and b/app/src/main/assets/op.ogg differ diff --git a/app/src/main/assets/open.ogg b/app/src/main/assets/open.ogg new file mode 100644 index 0000000..06afa23 Binary files /dev/null and b/app/src/main/assets/open.ogg differ diff --git a/app/src/main/assets/tenacity.ttf b/app/src/main/assets/tenacity.ttf new file mode 100644 index 0000000..2edf84b Binary files /dev/null and b/app/src/main/assets/tenacity.ttf differ diff --git a/app/src/main/assets/vt1.ogg b/app/src/main/assets/vt1.ogg new file mode 100644 index 0000000..ddfc10a Binary files /dev/null and b/app/src/main/assets/vt1.ogg differ diff --git a/app/src/main/assets/vt2.ogg b/app/src/main/assets/vt2.ogg new file mode 100644 index 0000000..45598bb Binary files /dev/null and b/app/src/main/assets/vt2.ogg differ diff --git a/app/src/main/assets/vt3.ogg b/app/src/main/assets/vt3.ogg new file mode 100644 index 0000000..1c94c72 Binary files /dev/null and b/app/src/main/assets/vt3.ogg differ diff --git a/app/src/main/assets/ys.ttf b/app/src/main/assets/ys.ttf new file mode 100644 index 0000000..da0dcf4 Binary files /dev/null and b/app/src/main/assets/ys.ttf differ diff --git a/app/src/main/assets/ztt.ttf b/app/src/main/assets/ztt.ttf new file mode 100644 index 0000000..85c1472 Binary files /dev/null and b/app/src/main/assets/ztt.ttf differ diff --git a/app/src/main/assets/zttt.ttf b/app/src/main/assets/zttt.ttf new file mode 100644 index 0000000..2edf84b Binary files /dev/null and b/app/src/main/assets/zttt.ttf differ diff --git a/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiCpp.java b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiCpp.java new file mode 100644 index 0000000..41ed246 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiCpp.java @@ -0,0 +1,79 @@ +package com.bytecat.algui.AlguiHacker; +import android.content.Context; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/22 21:48 + * @Describe 访问c++ + */ +public class AlguiCpp { + + public static final String TAG = "AlguiCpp"; + + //执行shell命令 + public static void shell(String shell) { + try { + Process process =Runtime.getRuntime().exec(shell, null, null); + process.waitFor(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + //执行外部cpp已编译好的so文件 + /** + * 执行外部cpp已编译好的so文件 普通执行 + * @param soFilePath so文件绝对路径 + */ + public static void exec(String soFilePath) { + if (soFilePath == null) { + return; + } + //授予so文件777权限 必须有执行权限否则无法运行 + shell("chmod 777 " + soFilePath); + //执行so文件 + shell(soFilePath); + } + + /** + * 执行外部cpp已编译好的so文件 普通执行 使用root权限执行 + * @param soFilePath so文件绝对路径 + */ + public static void exec_root(String soFilePath) { + if (soFilePath == null) { + return; + } + //授予so文件777权限 必须有执行权限否则无法运行 + shell("su -c \"" + "chmod 777 " + soFilePath + "\""); + //执行so文件 + shell("su -c \"" + soFilePath + "\""); + + } + + + /** + * 执行外部cpp已编译好的so文件 这将执行当前程序lib路径的so文件 + * @param libName 当前程序lib目录下要执行的so文件名 + */ + //注意:请确保当前程序安装包lib文件夹中的每个文件夹都包含该so文件,这样才能自动识别在不同处理器下执行不同so文件 + public static void exec_lib(Context context, String libName) { + if (libName == null) { + return; + } + exec(context.getApplicationInfo().nativeLibraryDir + "/" + libName); + } + + + /** + * 执行外部cpp已编译好的so文件 这将以Root权限执行当前程序lib路径的so文件 + * @param libName 当前程序lib目录下要执行的so文件名 + */ + //注意:请确保当前程序安装包lib文件夹中的每个文件夹都包含该so文件,这样才能自动识别在不同处理器下执行不同so文件 + public static void exec_lib_root(Context context, String libName) { + if (libName == null) { + return; + } + exec_root(context.getApplicationInfo().nativeLibraryDir + "/" + libName); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiMemTool.java b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiMemTool.java new file mode 100644 index 0000000..3b77e38 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiMemTool.java @@ -0,0 +1,885 @@ +package com.bytecat.algui.AlguiHacker; +import android.os.RemoteException; +import com.bytecat.algui.AlguiManager.AlguiLog; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/25 23:01 + * @Describe AlguiJava内存工具 + */ +public class AlguiMemTool { + + public static final String TAG = "AlguiMemTool"; + + // 内存区域 + public static final int RANGE_ALL = 0; // 所有内存区域 - 全部内存 + public static final int RANGE_JAVA_HEAP = 2; // Java 虚拟机堆内存 - jh内存 + public static final int RANGE_C_HEAP = 1; // C++ 堆内存 - ch内存 + public static final int RANGE_C_ALLOC = 4; // C++ 分配的内存 - ca内存 [已适配 android11+ scudo内存分配器] + public static final int RANGE_C_DATA = 8; // C++ 的数据段 - cd内存 + public static final int RANGE_C_BSS = 16; // C++ 未初始化的数据 - cb内存 + public static final int RANGE_ANONYMOUS = 32; // 匿名内存区域 - a内存 + public static final int RANGE_JAVA = 65536; // Java 虚拟机内存 - j内存 + public static final int RANGE_STACK = 64; // 栈内存区域 - s内存 + public static final int RANGE_ASHMEM = 524288; // Android 共享内存 - as内存 + public static final int RANGE_VIDEO = 1048576; // 视频内存区域 - v内存 + public static final int RANGE_OTHER = -2080896; // 其他内存区域 - o内存 + public static final int RANGE_B_BAD = 131072; // 错误的内存区域 - b内存 + public static final int RANGE_CODE_APP = 16384; // 应用程序代码区域 - xa内存 + public static final int RANGE_CODE_SYSTEM = 32768;// 系统代码区域 - xs内存 + // 基址头 + public static final int HEAD_XA = 0; //xa基址头 + public static final int HEAD_CD = 1; //cd基址头 + public static final int HEAD_CB = 2; //cb基址头 [bss] + // 数据类型 + public static final int TYPE_DWORD = 4; // DWORD 类型 - D类型 + public static final int TYPE_FLOAT = 16; // FLOAT 类型 - F类型 + public static final int TYPE_DOUBLE = 64; // DOUBLE 类型 - E类型 + public static final int TYPE_WORD = 2; // WORD 类型 - W类型 + public static final int TYPE_BYTE = 1; // BYTE 类型 - B类型 + public static final int TYPE_QWORD = 32; + + + + public static void MemoryOffsetWrite(String p0, int tYPE_BYTE, int p2, boolean p3) { + } // QWORD 类型 - Q类型 + + //初始化 + + + + //设置目标包名 【注意:这是初始化函数,不调用此函数的话其它内存操作均失效】 + public static int setPackageName(String packageName) { + int i = -1; + if (packageName != null) { + if (AlguiRootService.isConnect()) { + try { + i = AlguiRootService.getRootList().setPackageName(packageName); + } catch (RemoteException e) { + i = AlguiNativeMemTool.setPackageName(packageName); + } + } else { + i = AlguiNativeMemTool.setPackageName(packageName); + } + } + return i; + } + //获取进程ID + public static int getPID(String packageName) { + int pid = -1; + if (packageName != null) { + if (AlguiRootService.isConnect()) { + try { + pid = AlguiRootService.getRootList().getPID(packageName); + } catch (RemoteException e) { + pid = AlguiNativeMemTool.getPID(packageName); + } + } else { + pid = AlguiNativeMemTool.getPID(packageName); + } + } + return pid; + } + //设置安全写入启用状态 + public static void setIsSecureWrites(boolean sw) { + if (AlguiRootService.isConnect()) { + try { + AlguiRootService.getRootList().setIsSecureWrites(sw); + } catch (RemoteException e) { + AlguiNativeMemTool.setIsSecureWrites(sw); + } + } else { + AlguiNativeMemTool.setIsSecureWrites(sw); + } + } + + +public static byte[] readMemoryBulk(long addr, int size) { + // 若你已有实现,直接返回;若没实现,用旧方法兜底 + byte[] buf = new byte[size]; + for (int i = 0; i < size; i += 4) { + try { + int val = Integer.parseInt(getMemoryAddrData(addr + i, TYPE_DWORD)); + buf[i] = (byte)(val & 0xFF); + buf[i+1] = (byte)((val >> 8) & 0xFF); + buf[i+2] = (byte)((val >> 16) & 0xFF); + buf[i+3] = (byte)((val >> 24) & 0xFF); + } catch (Exception e) { break; } + } + return buf; +} + + + + //模块[动/静]态基址偏移内存修改 + + + //获取模块起始地址(基址) + public static long getModuleBaseAddr(String moduleName, int headType) { + long addr = -1; + if (moduleName != null) { + if (AlguiRootService.isConnect()) { + try { + addr = AlguiRootService.getRootList().getModuleBaseAddr(moduleName, headType); + } catch (RemoteException e) { + addr = AlguiNativeMemTool.getModuleBaseAddr(moduleName, headType); + } + } else { + addr = AlguiNativeMemTool.getModuleBaseAddr(moduleName, headType); + } + } + return addr; + } + //跳转指针 + public static long jump(long addr, int count) { + long result = -1; + + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().jump(addr, count); + } catch (RemoteException e) { + result = AlguiNativeMemTool.jump(addr, count); + } + } else { + result = AlguiNativeMemTool.jump(addr, count); + } + + return result; + } + + //跳转指针32位 + public static long jump32(long addr) { + long result = -1; + + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().jump32(addr); + } catch (RemoteException e) { + result = AlguiNativeMemTool.jump32(addr); + } + } else { + result = AlguiNativeMemTool.jump32(addr); + } + + return result; + } + //跳转指针64位 + public static long jump64(long addr) { + long result = -1; + + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().jump64(addr); + } catch (RemoteException e) { + result = AlguiNativeMemTool.jump64(addr); + } + } else { + result = AlguiNativeMemTool.jump64(addr); + } + + return result; + } + //设置指定内存地址指向的值 + public static int setMemoryAddrValue(String value, long addr, int type, boolean isFree,boolean isSecure) { + int result = -1; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().setMemoryAddrValue(value, addr, type, isFree,isSecure); + } catch (RemoteException e) { + result = AlguiNativeMemTool.setMemoryAddrValue(value, addr, type, isFree,isSecure); + } + } else { + result = AlguiNativeMemTool.setMemoryAddrValue(value, addr, type, isFree,isSecure); + } + } + return result; + } + //获取指定内存地址的数据 + public static String getMemoryAddrData(long addr, int type) { + String result = null; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getMemoryAddrData(addr, type); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getMemoryAddrData(addr, type); + } + } else { + result = AlguiNativeMemTool.getMemoryAddrData(addr, type); + } + + return result; + } + + + + + //内存搜索 + + + // 设置要搜索的内存区域 + public static void setMemoryArea(int memoryArea) { + + if (AlguiRootService.isConnect()) { + try { + AlguiRootService.getRootList().setMemoryArea(memoryArea); + } catch (RemoteException e) { + AlguiNativeMemTool.setMemoryArea(memoryArea); + } + } else { + AlguiNativeMemTool.setMemoryArea(memoryArea); + } + } + + // 内存搜索 【支持范围搜索 格式:最小值~最大值】 + public static long[] MemorySearch(String value, int type) { + long[] result = null; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().MemorySearch(value, type); + } catch (RemoteException e) { + result = AlguiNativeMemTool.MemorySearch(value, type); + } + } else { + result = AlguiNativeMemTool.MemorySearch(value, type); + } + } + return result; + } + + // 内存搜索范围值 【格式:最小值~最大值】 + public static long[] MemorySearchRange(String value, int type) { + long[] result = null; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().MemorySearchRange(value, type); + } catch (RemoteException e) { + result = AlguiNativeMemTool.MemorySearchRange(value, type); + } + } else { + result = AlguiNativeMemTool.MemorySearchRange(value, type); + } + } + + return result; + } + + // 联合内存搜索 【格式:值1;值2;值3;n个值:附近范围 示例:2D;3F;4E:50 或 2D;3F;4E没有范围则使用默认范围,两个范围符::代表按顺序搜索】 + public static long[] MemorySearchUnited(String value, int type) { + long[] result = null; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().MemorySearchUnited(value, type); + } catch (RemoteException e) { + result = AlguiNativeMemTool.MemorySearchUnited(value, type); + } + } else { + result = AlguiNativeMemTool.MemorySearchUnited(value, type); + } + } + return result; + } + + // 偏移改善 [筛选偏移处特征值 支持联合改善,范围改善] + public static long[] ImproveOffset(String value, int type, long offset) { + long[] result = null; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().ImproveOffset(value, type, offset); + } catch (RemoteException e) { + result = AlguiNativeMemTool.ImproveOffset(value, type, offset); + } + } else { + result = AlguiNativeMemTool.ImproveOffset(value, type, offset); + } + } + return result; + } + + // 偏移范围改善 [筛选偏移处只会在一个范围内变化的特征值] 【格式:最小值~最大值】 + public static long[] ImproveOffsetRange(String value, int type, long offset) { + long[] result = null; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().ImproveOffsetRange(value, type, offset); + } catch (RemoteException e) { + result = AlguiNativeMemTool.ImproveOffsetRange(value, type, offset); + } + } else { + result = AlguiNativeMemTool.ImproveOffsetRange(value, type, offset); + } + } + return result; + } + + // 偏移联合改善 [筛选偏移处永远只会为某些值的特征值] 【格式:值1;值2;n个值】 + public static long[] ImproveOffsetUnited(String value, int type, long offset) { + long[] result = null; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().ImproveOffsetUnited(value, type, offset); + } catch (RemoteException e) { + result = AlguiNativeMemTool.ImproveOffsetUnited(value, type, offset); + } + } else { + result = AlguiNativeMemTool.ImproveOffsetUnited(value, type, offset); + } + } + return result; + } + + // 改善 [支持联合改善,范围改善] + public static long[] ImproveValue(String value, int type) { + long[] result = null; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().ImproveValue(value, type); + } catch (RemoteException e) { + result = AlguiNativeMemTool.ImproveValue(value, type); + } + } else { + result = AlguiNativeMemTool.ImproveValue(value, type); + } + } + return result; + } + + // 结果偏移写入数据 【已对当前进程进行保护】 + public static int MemoryOffsetWrite(String value, int type, long offset, boolean isFree,boolean isSecure) { + int result = -1; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().MemoryOffsetWrite(value, type, offset, isFree,isSecure); + } catch (RemoteException e) { + result = AlguiNativeMemTool.MemoryOffsetWrite(value, type, offset, isFree,isSecure); + } + } else { + result = AlguiNativeMemTool.MemoryOffsetWrite(value, type, offset, isFree,isSecure); + } + } + return result; + } + + // 获取最终搜索结果数量 + public static int getResultCount() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getResultCount(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getResultCount(); + } + } else { + result = AlguiNativeMemTool.getResultCount(); + } + return result; + } + + // 获取最终搜索结果列表 + public static long[] getResultList() { + long[] result = null; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getResultList(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getResultList(); + } + } else { + result = AlguiNativeMemTool.getResultList(); + } + return result; + } + + // 打印最终搜索结果列表到指定文件 + public static int printResultListToFile(String filePath) { + int result = -1; + if (filePath != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().printResultListToFile(filePath); + } catch (RemoteException e) { + result = AlguiNativeMemTool.printResultListToFile(filePath); + } + } else { + result = AlguiNativeMemTool.printResultListToFile(filePath); + } + } + + return result; + } + + // 清空最终搜索结果列表 + public static int clearResultList() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().clearResultList(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.clearResultList(); + } + } else { + result = AlguiNativeMemTool.clearResultList(); + } + return result; + } + +//内存二次保护 + + // 设置存储二次保护地址 + public static void MemoryProtect(long addr) { + + if (AlguiRootService.isConnect()) { + try { + AlguiRootService.getRootList().MemoryProtect(addr); + } catch (RemoteException e) { + AlguiNativeMemTool.MemoryProtect(addr); + } + } else { + AlguiNativeMemTool.MemoryProtect(addr); + } + } + +//获取保护地址数量 +public static int getProtectionNum() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getProtectionNum(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getProtectionNum(); + } + } else { + result = AlguiNativeMemTool.getProtectionNum(); + } + return result; + } + + + + + + //冻结内存修改 + + // 设置冻结延迟时间(毫秒) + public static void setFreezeDelayMs(int delay) { + if (AlguiRootService.isConnect()) { + try { + AlguiRootService.getRootList().setFreezeDelayMs(delay); + } catch (RemoteException e) { + AlguiNativeMemTool.setFreezeDelayMs(delay); + } + } else { + AlguiNativeMemTool.setFreezeDelayMs(delay); + } + } + + // 获取冻结项目数量 + public static int getFreezeNum() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getFreezeNum(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getFreezeNum(); + } + } else { + result = AlguiNativeMemTool.getFreezeNum(); + } + return result; + } + + // 添加冻结项目 + public static int addFreezeItem(String value, long addr, int type) { + int result = -1; + if (value != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().addFreezeItem(value, addr, type); + } catch (RemoteException e) { + result = AlguiNativeMemTool.addFreezeItem(value, addr, type); + } + } else { + result = AlguiNativeMemTool.addFreezeItem(value, addr, type); + } + } + return result; + } + + // 移除指定冻结项目 + public static int removeFreezeItem(long addr) { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().removeFreezeItem(addr); + } catch (RemoteException e) { + result = AlguiNativeMemTool.removeFreezeItem(addr); + } + } else { + result = AlguiNativeMemTool.removeFreezeItem(addr); + } + return result; + } + + // 移除所有冻结项目 + public static int removeAllFreezeItem() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().removeAllFreezeItem(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.removeAllFreezeItem(); + } + } else { + result = AlguiNativeMemTool.removeAllFreezeItem(); + } + return result; + } + + // 启动所有冻结项目 + public static int startAllFreeze() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().startAllFreeze(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.startAllFreeze(); + } + } else { + result = AlguiNativeMemTool.startAllFreeze(); + } + return result; + } + + // 停止所有冻结项目 + public static int stopAllFreeze() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().stopAllFreeze(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.stopAllFreeze(); + } + } else { + result = AlguiNativeMemTool.stopAllFreeze(); + } + return result; + } + + // 将冻结项目列表打印到文件 + public static int printFreezeListToFile(String filePath) { + int result = -1; + if (filePath != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().printFreezeListToFile(filePath); + } catch (RemoteException e) { + result = AlguiNativeMemTool.printFreezeListToFile(filePath); + } + } else { + result = AlguiNativeMemTool.printFreezeListToFile(filePath); + } + } + return result; + } + + + + + + + //获取内存信息工具 + + + // 获取指定内存地址的Maps映射行 + public static String getMemoryAddrMapLine(long address) { + String result = null; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getMemoryAddrMapLine(address); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getMemoryAddrMapLine(address); + } + } else { + result = AlguiNativeMemTool.getMemoryAddrMapLine(address); + } + + return result; + } + + // 获取Maps映射行所在内存区域名称 + public static String getMapLineMemoryAreaName(String mapLine) { + String result = null; + if (mapLine != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getMapLineMemoryAreaName(mapLine); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getMapLineMemoryAreaName(mapLine); + } + } else { + result = AlguiNativeMemTool.getMapLineMemoryAreaName(mapLine); + } + } + return result; + } + + // 获取指定内存id的内存名称 + public static String getMemoryAreaIdName(int memid) { + String result = null; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getMemoryAreaIdName(memid); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getMemoryAreaIdName(memid); + } + } else { + result = AlguiNativeMemTool.getMemoryAreaIdName(memid); + } + + return result; + } + + // 获取当前内存名称 + public static String getMemoryAreaName() { + String result = null; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getMemoryAreaName(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getMemoryAreaName(); + } + } else { + result = AlguiNativeMemTool.getMemoryAreaName(); + } + return result; + } + + // 获取指定数据类型id的数据类型名称 + public static String getDataTypeName(int typeId) { + String result = null; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().getDataTypeName(typeId); + } catch (RemoteException e) { + result = AlguiNativeMemTool.getDataTypeName(typeId); + } + } else { + result = AlguiNativeMemTool.getDataTypeName(typeId); + } + + return result; + } + + + + + //超级用户工具 + + + // 杀掉指定包名的进程 + public static int killProcess_Root(String packageName) { + int result = -1; + if (packageName != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().killProcess_Root(packageName); + } catch (RemoteException e) { + result = AlguiNativeMemTool.killProcess_Root(packageName); + } + } else { + result = AlguiNativeMemTool.killProcess_Root(packageName); + } + } + return result; + } + + // 暂停指定包名的进程 + public static int stopProcess_Root(String packageName) { + int result = -1; + if (packageName != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().stopProcess_Root(packageName); + } catch (RemoteException e) { + result = AlguiNativeMemTool.stopProcess_Root(packageName); + } + } else { + result = AlguiNativeMemTool.stopProcess_Root(packageName); + } + } + return result; + } + + // 恢复被暂停的指定包名的进程 + public static int resumeProcess_Root(String packageName) { + int result = -1; + if (packageName != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().resumeProcess_Root(packageName); + } catch (RemoteException e) { + result = AlguiNativeMemTool.resumeProcess_Root(packageName); + } + } else { + result = AlguiNativeMemTool.resumeProcess_Root(packageName); + } + } + return result; + } + + // 杀掉所有inotify监视器 + public static void killAllInotify_Root() { + if (AlguiRootService.isConnect()) { + try { + AlguiRootService.getRootList().killAllInotify_Root(); + } catch (RemoteException e) { + AlguiNativeMemTool.killAllInotify_Root(); + } + } else { + AlguiNativeMemTool.killAllInotify_Root(); + } + } + + // 杀掉GG修改器 + public static int killGG_Root() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().killGG_Root(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.killGG_Root(); + } + } else { + result = AlguiNativeMemTool.killGG_Root(); + } + return result; + } + + // 杀掉XS脚本 + public static int killXscript_Root() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().killXscript_Root(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.killXscript_Root(); + } + } else { + result = AlguiNativeMemTool.killXscript_Root(); + } + return result; + } + + // 重启手机 + public static int rebootsystem_Root() { + int result = -1; + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().rebootsystem_Root(); + } catch (RemoteException e) { + result = AlguiNativeMemTool.rebootsystem_Root(); + } + } else { + result = AlguiNativeMemTool.rebootsystem_Root(); + } + return result; + } + + // 静默安装指定路径的APK安装包 + public static int installapk_Root(String apkPackagePath) { + int result = -1; + if (apkPackagePath != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().installapk_Root(apkPackagePath); + } catch (RemoteException e) { + result = AlguiNativeMemTool.installapk_Root(apkPackagePath); + } + } else { + result = AlguiNativeMemTool.installapk_Root(apkPackagePath); + } + } + return result; + } + + // 静默卸载指定包名的APK软件 + public static int uninstallapk_Root(String packageName) { + int result = -1; + if (packageName != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().uninstallapk_Root(packageName); + } catch (RemoteException e) { + result = AlguiNativeMemTool.uninstallapk_Root(packageName); + } + } else { + result = AlguiNativeMemTool.uninstallapk_Root(packageName); + } + } + return result; + } + + // 执行命令 + public static int Cmd(String command) { + int result = -1; + if (command != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().Cmd(command); + } catch (RemoteException e) { + result = AlguiNativeMemTool.Cmd(command); + } + } else { + result = AlguiNativeMemTool.Cmd(command); + } + } + return result; + } + + // 执行超级命令 + public static int Cmd_Root(String command) { + int result = -1; + if (command != null) { + if (AlguiRootService.isConnect()) { + try { + result = AlguiRootService.getRootList().Cmd_Root(command); + } catch (RemoteException e) { + result = AlguiNativeMemTool.Cmd_Root(command); + } + } else { + result = AlguiNativeMemTool.Cmd_Root(command); + } + } + return result; + } + + //执行JNI层的功能函数 参数:功能ID,该功能开关状态,修改值(可选 对于在拖动条或输入框自定义修改值) + public static void JniSwitch(int id, boolean isSwitch, String value) { + if(value==null)value="0"; + if (AlguiRootService.isConnect()) { + try { + AlguiRootService.getRootList().JniSwitch(id, isSwitch, value); + } catch (RemoteException e) { + AlguiNativeMemTool.JniSwitch(id, isSwitch, value); + } + } else { + AlguiNativeMemTool.JniSwitch(id, isSwitch, value); + } + } + + //HOOK + ///Java传递调用JNI对应HOOK功能 (不支持root) + public static void JniHook(int id, boolean isSwitch, double value) { + AlguiNativeMemTool.JniHook(id, isSwitch, value); + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiNativeMemTool.java b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiNativeMemTool.java new file mode 100644 index 0000000..8a55384 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiNativeMemTool.java @@ -0,0 +1,86 @@ +package com.bytecat.algui.AlguiHacker; +import com.bytecat.algui.AlguiTools.AlguiToolNative; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/26 02:35 + * @Describe Algui内存工具JNI映射接口 + */ +public class AlguiNativeMemTool { + + public static final String TAG = "AlguiNativeMemTool"; + static{AlguiToolNative.loadLibrary("Algui");} + + //初始化 + public static native int setPackageName(String packageName); // 设置目标包名 【注意:这是初始化函数,不调用此函数的话其它内存操作均失效】 + public static native int getPID(String packageName); // 获取进程ID + public static native void setIsSecureWrites(boolean sw);// 设置安全写入启用状态 + + //模块[动/静]态基址偏移内存修改 + public static native long getModuleBaseAddr(String moduleName, int headType); // 获取模块起始地址(基址) + public static native long jump(long addr,int count); // 跳转指针 + public static native long jump32(long addr); // 跳转指针 [32位] + public static native long jump64(long addr); // 跳转指针 [64位] + public static native int setMemoryAddrValue(String value, long addr, int type, boolean isFree,boolean isSecure); // 设置指定内存地址指向的值 🛡️该方法已对当前进程进行保护 防止GG模糊🛡️ + public static native String getMemoryAddrData(long addr, int type); // 获取指定内存地址的数据 + + + //内存搜索 + public static native void setMemoryArea(int memoryArea); // 设置要搜索的内存区域 + public static native long[] MemorySearch(String value, int type); // 内存搜索 【支持范围搜索 格式:最小值~最大值】 + public static native long[] MemorySearchRange(String value, int type); // 内存搜索范围值 【格式:最小值~最大值】 + public static native long[] MemorySearchUnited(String value, int type);//联合内存搜索 【格式:值1;值2;值3;n个值:附近范围 示例:2D;3F;4E:50 或 2D;3F;4E没有范围则使用默认范围,两个范围符::代表按顺序搜索 (同GG) 并且值也支持范围例如1~2;3:64】 + public static native long[] ImproveOffset(String value, int type, long offset);//偏移改善 [筛选偏移处特征值 支持联合改善,范围改善] + public static native long[] ImproveOffsetRange(String value, int type, long offset);//偏移范围改善 [筛选偏移处只会在一个范围内变化的特征值] 【格式:最小值~最大值 (同GG)】 + public static native long[] ImproveOffsetUnited(String value, int type, long offset);//偏移联合改善 [筛选偏移处永远只会为某些值的特征值] 【格式:值1;值2;n个值; 示例:2D;3F;4E 或 2D;3~6F;9E 注:联合改善不支持附近范围和顺序改善】 + public static native long[] ImproveValue(String value, int type);//改善 [支持联合改善,范围改善] + public static native int MemoryOffsetWrite(String value, int type, long offset, boolean isFree,boolean isSecure); // 结果偏移写入数据 🛡️该方法已对当前进程进行保护 防止GG模糊🛡️ + public static native int getResultCount(); // 获取最终搜索结果数量 + public static native long[] getResultList(); // 获取最终搜索结果列表 + public static native int printResultListToFile(String filePath); // 打印最终搜索结果列表到指定文件 + public static native int clearResultList(); // 清空最终搜索结果列表 + +//内存二次保护 +public static native void MemoryProtect(long addr); + public static native int getProtectionNum(); + + //冻结内存修改 + public static native void setFreezeDelayMs(int delay); // 设置冻结延迟时间(毫秒) + public static native int getFreezeNum(); // 获取冻结项目数量 + public static native int addFreezeItem(String value, long addr, int type); // 添加冻结项目 + public static native int removeFreezeItem(long addr); // 移除指定冻结项目 + public static native int removeAllFreezeItem(); // 移除所有冻结项目 + public static native int startAllFreeze(); // 启动所有冻结项目 + public static native int stopAllFreeze(); // 停止所有冻结项目 + public static native int printFreezeListToFile(String filePath); // 将冻结项目列表打印到文件 + + //获取内存信息相关工具 + public static native String getMemoryAddrMapLine(long address); // 获取指定内存地址的Maps映射行 + public static native String getMapLineMemoryAreaName(String mapLine); // 获取Maps映射行所在内存区域名称 + public static native String getMemoryAreaIdName(int memid); // 获取指定内存id的内存名称 + public static native String getMemoryAreaName(); // 获取当前内存名称 + public static native String getDataTypeName(int typeId); // 获取指定数据类型id的数据类型名称 + + //完全需要ROOT权限的操作 + //PS:告诉一下菜鸟,这些操作涉及到跨进程和系统操作,所以必须完全ROOT,直装也没用 + //--kill-- + public static native int killProcess_Root(String packageName); // 杀掉指定包名的进程 + public static native int stopProcess_Root(String packageName); // 暂停指定包名的进程 (此方法对于执行者自身进程无需Root) + public static native int resumeProcess_Root(String packageName); // 恢复被暂停的指定包名的进程 (此方法对于执行者自身进程无需Root) + public static native void killAllInotify_Root(); // 杀掉所有inotify监视器,防止游戏监视文件变化 + public static native int killGG_Root(); // 杀掉GG修改器 + public static native int killXscript_Root(); // 杀掉XS脚本 + //--Other-- + public static native int rebootsystem_Root(); // 重启手机 + public static native int installapk_Root(String apkPackagePath); // 静默安装指定路径的APK安装包 + public static native int uninstallapk_Root(String packageName); // 静默卸载指定包名的APK软件 + public static native int Cmd(String command);//执行命令 + public static native int Cmd_Root(String command);//执行超级命令 + + //执行JNI层的功能函数 参数:功能ID,该功能开关状态,修改值(可选 对于在拖动条或输入框自定义修改值) + public static native void JniSwitch(int id,boolean isSwitch,String value); + + //执行控制JNI层的HOOK(不支持root) 参数:功能ID,该功能开关状态,修改值(可选 对于在拖动条或输入框自定义修改值) + public static native void JniHook(int id,boolean isSwitch,double value); + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootClient.java b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootClient.java new file mode 100644 index 0000000..c2dc481 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootClient.java @@ -0,0 +1,446 @@ +package com.bytecat.algui.AlguiHacker; +import android.annotation.NonNull; +import android.content.Intent; +import android.os.IBinder; +import android.os.RemoteException; +import com.topjohnwu.superuser.ipc.RootService; +import com.bytecat.algui.AlguiTools.AlguiToolNative; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/22 21:48 + * @Describe Algui Root客户端 实现IPC通道方法接口传递给服务端 + */ +public class AlguiRootClient extends RootService { + + public static final String TAG = "AlguiRootClient"; + + //实现Algui JRoot服务端的IPC接口函数 下面方法将在ROOT环境下调用 + @Override + public IBinder onBind(@NonNull Intent intent) { + return new AlguiRootIPC.Stub() { + //=======AlguiROOT内存修改工具======== + @Override // 设置包名 + public int setPackageName(String packageName) throws RemoteException { return AlguiNativeMemTool.setPackageName(packageName); } + + @Override // 获取进程ID + public int getPID(String packageName) throws RemoteException { return AlguiNativeMemTool.getPID(packageName); } + + @Override // 设置是否启用安全写入 + public void setIsSecureWrites(boolean sw) throws RemoteException { AlguiNativeMemTool.setIsSecureWrites(sw); } + + @Override // 获取模块基址 + public long getModuleBaseAddr(String moduleName, int headType) throws RemoteException { return AlguiNativeMemTool.getModuleBaseAddr(moduleName, headType); } + + @Override // 跳转指针 + public long jump(long addr,int count) throws RemoteException { return AlguiNativeMemTool.jump(addr,count); } + + @Override // 32位跳转 + public long jump32(long addr) throws RemoteException { return AlguiNativeMemTool.jump32(addr); } + + @Override // 64位跳转 + public long jump64(long addr) throws RemoteException { return AlguiNativeMemTool.jump64(addr); } + + @Override // 设置内存地址值 + public int setMemoryAddrValue(String value, long addr, int type, boolean isFree,boolean isSecure) throws RemoteException { return AlguiNativeMemTool.setMemoryAddrValue(value, addr, type, isFree,isSecure); } + + @Override // 获取内存地址数据 + public String getMemoryAddrData(long addr, int type) throws RemoteException { return AlguiNativeMemTool.getMemoryAddrData(addr, type); } + + @Override // 设置内存区域 + public void setMemoryArea(int memoryArea) throws RemoteException { AlguiNativeMemTool.setMemoryArea(memoryArea); } + + @Override // 内存搜索 + public long[] MemorySearch(String value, int type) throws RemoteException { return AlguiNativeMemTool.MemorySearch(value, type); } + + @Override // 内存范围搜索 + public long[] MemorySearchRange(String value, int type) throws RemoteException { return AlguiNativeMemTool.MemorySearchRange(value, type); } + + @Override // 联合内存搜索 + public long[] MemorySearchUnited(String value, int type) throws RemoteException { return AlguiNativeMemTool.MemorySearchUnited(value, type); } + + @Override // 改进偏移 + public long[] ImproveOffset(String value, int type, long offset) throws RemoteException { return AlguiNativeMemTool.ImproveOffset(value, type, offset); } + + @Override // 改进范围偏移 + public long[] ImproveOffsetRange(String value, int type, long offset) throws RemoteException { return AlguiNativeMemTool.ImproveOffsetRange(value, type, offset); } + + @Override // 改进联合偏移 + public long[] ImproveOffsetUnited(String value, int type, long offset) throws RemoteException { return AlguiNativeMemTool.ImproveOffsetUnited(value, type, offset); } + + @Override // 改进值 + public long[] ImproveValue(String value, int type) throws RemoteException { return AlguiNativeMemTool.ImproveValue(value, type); } + + @Override // 内存偏移写入 + public int MemoryOffsetWrite(String value, int type, long offset, boolean isFree,boolean isSecure) throws RemoteException { return AlguiNativeMemTool.MemoryOffsetWrite(value, type, offset, isFree, isSecure); } + + @Override // 获取结果数量 + public int getResultCount() throws RemoteException { return AlguiNativeMemTool.getResultCount(); } + + @Override // 获取结果列表 + public long[] getResultList() throws RemoteException { return AlguiNativeMemTool.getResultList(); } + + @Override // 打印结果列表到文件 + public int printResultListToFile(String filePath) throws RemoteException { return AlguiNativeMemTool.printResultListToFile(filePath); } + + @Override // 清除结果列表 + public int clearResultList() throws RemoteException { return AlguiNativeMemTool.clearResultList(); } + + @Override // 设置二次保护地址 + public void MemoryProtect(long addr) throws RemoteException { AlguiNativeMemTool.MemoryProtect(addr); } + + @Override // 获取保护数量 + public int getProtectionNum() throws RemoteException { return AlguiNativeMemTool.getProtectionNum(); } + + @Override // 设置冻结延迟 + public void setFreezeDelayMs(int delay) throws RemoteException { AlguiNativeMemTool.setFreezeDelayMs(delay); } + + @Override // 获取冻结数量 + public int getFreezeNum() throws RemoteException { return AlguiNativeMemTool.getFreezeNum(); } + + @Override // 添加冻结项 + public int addFreezeItem(String value, long addr, int type) throws RemoteException { return AlguiNativeMemTool.addFreezeItem(value, addr, type); } + + @Override // 移除冻结项 + public int removeFreezeItem(long addr) throws RemoteException { return AlguiNativeMemTool.removeFreezeItem(addr); } + + @Override // 移除所有冻结项 + public int removeAllFreezeItem() throws RemoteException { return AlguiNativeMemTool.removeAllFreezeItem(); } + + @Override // 启动所有冻结 + public int startAllFreeze() throws RemoteException { return AlguiNativeMemTool.startAllFreeze(); } + + @Override // 停止所有冻结 + public int stopAllFreeze() throws RemoteException { return AlguiNativeMemTool.stopAllFreeze(); } + + @Override // 打印冻结列表到文件 + public int printFreezeListToFile(String filePath) throws RemoteException { return AlguiNativeMemTool.printFreezeListToFile(filePath); } + + @Override // 获取内存地址映射行 + public String getMemoryAddrMapLine(long address) throws RemoteException { return AlguiNativeMemTool.getMemoryAddrMapLine(address); } + + @Override // 获取映射行的内存区域名 + public String getMapLineMemoryAreaName(String mapLine) throws RemoteException { return AlguiNativeMemTool.getMapLineMemoryAreaName(mapLine); } + + @Override // 获取内存区域ID名称 + public String getMemoryAreaIdName(int memid) throws RemoteException { return AlguiNativeMemTool.getMemoryAreaIdName(memid); } + + @Override // 获取内存区域名称 + public String getMemoryAreaName() throws RemoteException { return AlguiNativeMemTool.getMemoryAreaName(); } + + @Override // 获取数据类型名称 + public String getDataTypeName(int typeId) throws RemoteException { return AlguiNativeMemTool.getDataTypeName(typeId); } + + @Override // 杀死进程(Root权限) + public int killProcess_Root(String packageName) throws RemoteException { return AlguiNativeMemTool.killProcess_Root(packageName); } + + @Override // 杀死所有Inotify(Root权限) + public void killAllInotify_Root() throws RemoteException { AlguiNativeMemTool.killAllInotify_Root(); } + + @Override // 停止进程(Root权限) + public int stopProcess_Root(String packageName) throws RemoteException { return AlguiNativeMemTool.stopProcess_Root(packageName); } + + @Override // 恢复进程(Root权限) + public int resumeProcess_Root(String packageName) throws RemoteException { return AlguiNativeMemTool.resumeProcess_Root(packageName); } + + @Override // 杀死GG(Root权限) + public int killGG_Root() throws RemoteException { return AlguiNativeMemTool.killGG_Root(); } + + @Override // 杀死Xscript(Root权限) + public int killXscript_Root() throws RemoteException { return AlguiNativeMemTool.killXscript_Root(); } + + @Override // 重启系统(Root权限) + public int rebootsystem_Root() throws RemoteException { return AlguiNativeMemTool.rebootsystem_Root(); } + + @Override // 安装APK(Root权限) + public int installapk_Root(String apkPackagePath) throws RemoteException { return AlguiNativeMemTool.installapk_Root(apkPackagePath); } + + @Override // 卸载APK(Root权限) + public int uninstallapk_Root(String packageName) throws RemoteException { return AlguiNativeMemTool.uninstallapk_Root(packageName); } + + @Override // 执行命令 + public int Cmd(String command) throws RemoteException { return AlguiNativeMemTool.Cmd(command); } + + @Override // 执行Root命令 + public int Cmd_Root(String command) throws RemoteException { return AlguiNativeMemTool.Cmd_Root(command); } + + @Override // 执行JNI层的功能 + public void JniSwitch(int id,boolean isSwitch,String value) throws RemoteException { AlguiNativeMemTool.JniSwitch(id,isSwitch,value); } + + + + /* @Override + public void setIsSecureWrites(boolean sw) throws RemoteException { + AlguiMemTool.setIsSecureWrites(sw); + } + + @Override + public long[] MemorySearchUnited(String value, int type) throws RemoteException { + return AlguiMemTool.MemorySearchUnited(value,type); + } + + @Override + public long[] ImproveOffsetRange(String value, int type, long offset) throws RemoteException { + return AlguiMemTool.ImproveOffsetRange(value,type,offset); + } + + @Override + public long[] ImproveOffsetUnited(String value, int type, long offset) throws RemoteException { + return AlguiMemTool.ImproveOffsetUnited(value,type,offset); + } + + @Override + public long[] ImproveValue(String value, int type) throws RemoteException { + return AlguiMemTool.ImproveValue(value,type); + } + + @Override + public int stopProcess_Root(String packageName) throws RemoteException { + return AlguiMemTool.stopProcess_Root(packageName); + } + + @Override + public int resumeProcess_Root(String packageName) throws RemoteException { + return AlguiMemTool.resumeProcess_Root(packageName); + } + + @Override + public int Cmd(String command) throws RemoteException { + return AlguiMemTool.Cmd(command); + } + + @Override + public int Cmd_Root(String command) throws RemoteException { + return AlguiMemTool.Cmd_Root(command); + } + + + @Override + public int setPackageName(String packageName) throws RemoteException { + //设置包名 + return AlguiMemTool.setPackageName(packageName); + } + + @Override + public int getPID(String packageName) throws RemoteException { + //获取进程ID + return AlguiMemTool.getPID(packageName); + } + + @Override + public long getModuleBaseAddr(String moduleName, int headType) throws RemoteException { + //获取模块基址 + return AlguiMemTool.getModuleBaseAddr(moduleName,headType); + } + + @Override + public long jump32(long addr) throws RemoteException { + //跳转指针 32 + return AlguiMemTool.jump32(addr); + } + + @Override + public long jump64(long addr) throws RemoteException { + //跳转指针 64 + return AlguiMemTool.jump64(addr); + } + + @Override + public int setMemoryAddrValue(String value, long addr, int type, boolean isFree) throws RemoteException { + //修改指定地址的指定类型的值 + return AlguiMemTool.setMemoryAddrValue(value,addr,type,isFree); + } + + @Override + public String getMemoryAddrData(long addr, int type) throws RemoteException { + //获取指定地址的指定类型的值 + return AlguiMemTool.getMemoryAddrData(addr, type); + } + + @Override + public void setMemoryArea(int memoryArea) throws RemoteException { + //设置内存范围 + AlguiMemTool.setMemoryArea(memoryArea); + } + + @Override + public long[] MemorySearch(String value, int type) throws RemoteException { + //内存搜索 + return AlguiMemTool.MemorySearch(value, type); + } + + @Override + public long[] MemorySearchRange(String value, int type) throws RemoteException { + //内存搜索范围值 + return AlguiMemTool.MemorySearchRange(value, type); + } + + @Override + public long[] ImproveOffset(String value, int type, long offset) throws RemoteException { + //搜索结果偏移筛选特征码 + return AlguiMemTool.ImproveOffset(value, type, offset); + } + + + @Override + public int MemoryOffsetWrite(String value, int type, long offset, boolean isFree) throws RemoteException { + //修改筛选结果开始偏移的指定类型的值 + return AlguiMemTool.MemoryOffsetWrite(value,type,offset,isFree); + } + + @Override + public int getResultCount() throws RemoteException { + //获取搜索结果数量 + return AlguiMemTool.getResultCount(); + } + + @Override + public long[] getResultList() throws RemoteException { + //获取搜索结果列表 + return AlguiMemTool.getResultList(); + } + + @Override + public int printResultListToFile(String filePath) throws RemoteException { + //将搜索结果列表打印到指定文件中 + return AlguiMemTool.printResultListToFile(filePath); + } + + @Override + public int clearResultList() throws RemoteException { + //清除搜索结果列表 + return AlguiMemTool.clearResultList(); + } + + @Override + public void setFreezeDelayMs(int delay) throws RemoteException { + //设置冻结延迟 + AlguiMemTool.setFreezeDelayMs(delay); + } + + @Override + public int getFreezeNum() throws RemoteException { + //获取冻结数量 + return AlguiMemTool.getFreezeNum(); + } + + @Override + public int addFreezeItem(String value, long addr, int type) throws RemoteException { + //添加一个冻结项目 + return AlguiMemTool.addFreezeItem(value,addr,type); + } + + @Override + public int removeFreezeItem(long addr) throws RemoteException { + //移除一个冻结项目 + return AlguiMemTool.removeFreezeItem(addr); + } + + @Override + public int removeAllFreezeItem() throws RemoteException { + //移除所有冻结项目 + return AlguiMemTool.removeAllFreezeItem(); + } + + @Override + public int startAllFreeze() throws RemoteException { + //开始冻结 + return AlguiMemTool.startAllFreeze(); + } + + @Override + public int stopAllFreeze() throws RemoteException { + //停止冻结 + return AlguiMemTool.stopAllFreeze(); + } + + @Override + public int printFreezeListToFile(String filePath) throws RemoteException { + //将冻结列表打印到指定文件 + return AlguiMemTool.printFreezeListToFile(filePath); + } + + @Override + public String getMemoryAddrMapLine(long address) throws RemoteException { + //获取指定内存地址的Maps映射行 + return AlguiMemTool.getMemoryAddrMapLine(address); + } + + @Override + public String getMapLineMemoryAreaName(String mapLine) throws RemoteException { + //获取Maps映射行所在内存区域名称 + return AlguiMemTool.getMapLineMemoryAreaName(mapLine); + } + + @Override + public String getMemoryAreaIdName(int memid) throws RemoteException { + //获取指定内存id的内存名称 + return AlguiMemTool.getMemoryAreaIdName(memid); + } + + @Override + public String getMemoryAreaName() throws RemoteException { + //获取当前内存名称 + return AlguiMemTool.getMemoryAreaName(); + } + + @Override + public String getDataTypeName(int typeId) throws RemoteException { + //获取指定数据类型id的数据类型名称 + return AlguiMemTool.getDataTypeName(typeId); + } + + @Override + public int killprocess_Root(String packageName) throws RemoteException { + //杀掉指定包名的进程 + return AlguiMemTool.killprocess_Root(packageName); + } + + @Override + public void killAllInotify_Root() throws RemoteException { + //杀掉所有inotify监视器,防止游戏监视文件变化 + AlguiMemTool.killAllInotify_Root(); + } + + @Override + public int killGG_Root() throws RemoteException { + //杀掉GG修改器 + return AlguiMemTool.killGG_Root(); + } + + @Override + public int killXscript_Root() throws RemoteException { + //杀掉XS脚本 + return AlguiMemTool.killXscript_Root(); + } + + @Override + public int rebootsystem_Root() throws RemoteException { + //重启手机 + return AlguiMemTool.rebootsystem_Root(); + } + + @Override + public int installapk_Root(String apkPackagePath) throws RemoteException { + //静默安装指定路径的APK安装包 + return AlguiMemTool.installapk_Root(apkPackagePath); + } + + @Override + public int uninstallapk_Root(String packageName) throws RemoteException { + //静默卸载指定包名的APK软件 + return AlguiMemTool.uninstallapk_Root(packageName); + } + + + @Override + public void NativeDebug(int id) throws RemoteException { + //Native调试专用 + AlguiMemTool.NativeDebug(id); + }*/ + + + + }; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootIPC.aidl b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootIPC.aidl new file mode 100644 index 0000000..ebac8fd --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootIPC.aidl @@ -0,0 +1,72 @@ +package com.bytecat.algui.AlguiHacker; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/22 21:48 + * @Describe Algui ipc通道 声明支持root环境执行的方法 + */ +interface AlguiRootIPC { + + //=======AlguiROOT内存修改工具======== + // 初始化 + int setPackageName(in String packageName); // 设置目标包名 【注意:这是初始化函数,不调用此函数的话其它内存操作均失效】 + int getPID(in String packageName); // 获取进程ID + void setIsSecureWrites(boolean sw);// 设置安全写入启用状态 + // 模块[动/静]态基址偏移内存修改 + long getModuleBaseAddr(in String moduleName, int headType); // 获取模块起始地址(基址) + long jump(long addr,int count); // 跳转指针 + long jump32(long addr); // 跳转指针 [32位] + long jump64(long addr); // 跳转指针 [64位] + int setMemoryAddrValue(in String value, long addr, int type, boolean isFree,boolean isSecure); // 设置指定内存地址指向的值 🛡️该方法已对当前进程进行保护 防止GG模糊🛡️ + String getMemoryAddrData(long addr, int type); // 获取指定内存地址的数据 + // 内存搜索 + void setMemoryArea(int memoryArea); // 设置要搜索的内存区域 + long[] MemorySearch(in String value, int type); // 内存搜索 + long[] MemorySearchRange(in String value, int type); // 内存搜索范围值 + long[] MemorySearchUnited(in String value, int type); // 联合内存搜索 + long[] ImproveOffset(in String value, int type, long offset); // 偏移改善 + long[] ImproveOffsetRange(in String value, int type, long offset); // 偏移范围改善 + long[] ImproveOffsetUnited(in String value, int type, long offset); // 偏移联合改善 + long[] ImproveValue(in String value, int type); // 改善 + int MemoryOffsetWrite(String value, int type, long offset, boolean isFree,boolean isSecure); // 结果偏移写入数据 + int getResultCount(); // 获取最终搜索结果数量 + long[] getResultList(); // 获取最终搜索结果列表 + int printResultListToFile(in String filePath); // 打印最终搜索结果列表到指定文件 + int clearResultList(); // 清空最终搜索结果列表 + //二次内存保护 + void MemoryProtect(long addr); + int getProtectionNum(); + // 冻结内存修改 + //FreezeItem[] getFreezeList(); // 获取冻结项目列表 !不支持! + void setFreezeDelayMs(int delay); // 设置冻结延迟时间(毫秒) + int getFreezeNum(); // 获取冻结项目数量 + int addFreezeItem(in String value, long addr, int type); // 添加冻结项目 + int removeFreezeItem(long addr); // 移除指定冻结项目 + int removeAllFreezeItem(); // 移除所有冻结项目 + int startAllFreeze(); // 启动所有冻结项目 + int stopAllFreeze(); // 停止所有冻结项目 + int printFreezeListToFile(in String filePath); // 将冻结项目列表打印到文件 + // 获取内存信息相关工具 + String getMemoryAddrMapLine(long address); // 获取指定内存地址的Maps映射行 + String getMapLineMemoryAreaName(in String mapLine); // 获取Maps映射行所在内存区域名称 + String getMemoryAreaIdName(int memid); // 获取指定内存id的内存名称 + String getMemoryAreaName(); // 获取当前内存名称 + String getDataTypeName(int typeId); // 获取指定数据类型id的数据类型名称 + // 完全需要ROOT权限的操作 + // PS:告诉一下菜鸟,这些操作涉及到跨进程和系统操作,所以必须完全ROOT,直装也没用 + //--kill-- + int killProcess_Root(in String packageName); // 杀掉指定包名的进程 + void killAllInotify_Root(); // 杀掉所有inotify监视器,防止游戏监视文件变化 + int stopProcess_Root(String packageName); // 暂停指定包名的进程 (此方法对于执行者自身进程无需Root) + int resumeProcess_Root(String packageName); // 恢复被暂停的指定包名的进程 (此方法对于执行者自身进程无需Root) + int killGG_Root(); // 杀掉GG修改器 + int killXscript_Root(); // 杀掉XS脚本 + //--Other-- + int rebootsystem_Root(); // 重启手机 + int installapk_Root(in String apkPackagePath); // 静默安装指定路径的APK安装包 + int uninstallapk_Root(in String packageName); // 静默卸载指定包名的APK软件 + int Cmd(in String command);//执行命令 + int Cmd_Root(in String command);//执行超级命令 + + void JniSwitch(int id,boolean isSwitch,String value);//执行JNI层的功能 + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootService.java b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootService.java new file mode 100644 index 0000000..88143a8 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiHacker/AlguiRootService.java @@ -0,0 +1,45 @@ +package com.bytecat.algui.AlguiHacker; +import android.content.ComponentName; +import android.content.ServiceConnection; +import android.os.IBinder; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiManager.AlguiLog; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/22 21:48 + * @Describe Algui Root服务端 + */ +public class AlguiRootService implements ServiceConnection { + + public static final String TAG = "AlguiRootService"; + private static AlguiCallback.RootService call; + private static boolean isConnect;//是否已连接Root + private static AlguiRootIPC ipc;//IPC通道 + //是否已连接Root + public static boolean isConnect() {return isConnect;} + //获取Root环境的方法列表 + public static AlguiRootIPC getRootList() {return ipc;} + //设置ROOT状态回调接口 + public static void setCallBack(AlguiCallback.RootService c) {call = c;} + + //连接成功 + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + //IBinder转换为Stub接口 + ipc = AlguiRootIPC.Stub.asInterface(service); + isConnect = true;//已连接 + AlguiLog.d(TAG,"AlguiRoot权限连接成功"); + if (call != null) + call.rootService(true); + + } + + //断开连接 + @Override + public void onServiceDisconnected(ComponentName name) { + isConnect = false;//断开连接 + AlguiLog.d(TAG,"AlguiRoot权限断开连接"); + if (call != null) + call.rootService(false); + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiHacker/Vector2.java b/app/src/main/java/com/bytecat/algui/AlguiHacker/Vector2.java new file mode 100644 index 0000000..6924e70 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiHacker/Vector2.java @@ -0,0 +1,64 @@ +package com.bytecat.algui.AlguiHacker; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/27 00:48 + * @Describe Algui二维 + */ +public class Vector2 { + + public static final String TAG = "Vector2"; + public float x; + public float y; + public Vector2() { + this.x = 0; + this.y = 0; + } + public Vector2(float x, float y) { + this.x = x; + this.y = y; + } + + //加法运算 + public Vector2 add(Vector2 other) { + return new Vector2(this.x + other.x, this.y + other.y); + } + + //减法运算减 + public Vector2 subtract(Vector2 other) { + return new Vector2(this.x - other.x, this.y - other.y); + } + + //向量缩放 + public Vector2 scale(float factor) { + return new Vector2(this.x * factor, this.y * factor); + } + + //点积运算 + public float dot(Vector2 other) { + return this.x * other.x + this.y * other.y; + } + + //求向量的模(长度) + public float magnitude() { + return (float) Math.sqrt(x * x + y * y); + } + + //归一化 + public Vector2 normalize() { + float magnitude = magnitude(); + if (magnitude == 0) { + return new Vector2(0, 0); //防止除零 + } + return new Vector2(this.x / magnitude, this.y / magnitude); + } + + //输出字符串形式 + @Override + public String toString() { + return "Vector2(" + x + ", " + y + ")"; + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiHacker/Vector3.java b/app/src/main/java/com/bytecat/algui/AlguiHacker/Vector3.java new file mode 100644 index 0000000..47c07bf --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiHacker/Vector3.java @@ -0,0 +1,77 @@ +package com.bytecat.algui.AlguiHacker; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/27 00:48 + * @Describe Algui三维 + */ +public class Vector3 { + + public static final String TAG = "Vector3"; + public float x; + public float y; + public float z; + + public Vector3() { + this.x = 0; + this.y = 0; + this.z = 0; + } + + public Vector3(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + //加法运算 + public Vector3 add(Vector3 other) { + return new Vector3(this.x + other.x, this.y + other.y, this.z + other.z); + } + + //减法运算 + public Vector3 subtract(Vector3 other) { + return new Vector3(this.x - other.x, this.y - other.y, this.z - other.z); + } + + //向量缩放 + public Vector3 scale(float factor) { + return new Vector3(this.x * factor, this.y * factor, this.z * factor); + } + + //点积运算 + public float dot(Vector3 other) { + return this.x * other.x + this.y * other.y + this.z * other.z; + } + + //叉积运算 + public Vector3 cross(Vector3 other) { + float crossX = this.y * other.z - this.z * other.y; + float crossY = this.z * other.x - this.x * other.z; + float crossZ = this.x * other.y - this.y * other.x; + return new Vector3(crossX, crossY, crossZ); + } + + //求向量的模(长度) + public float magnitude() { + return (float) Math.sqrt(x * x + y * y + z * z); + } + + //归一化 + public Vector3 normalize() { + float magnitude = magnitude(); + if (magnitude == 0) { + return new Vector3(0, 0, 0); //防止除零 + } + return new Vector3(this.x / magnitude, this.y / magnitude, this.z / magnitude); + } + + //输出字符串形式 + @Override + public String toString() { + return "Vector3(" + x + ", " + y + ", " + z + ")"; + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiAssets.java b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiAssets.java new file mode 100644 index 0000000..f7bcb58 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiAssets.java @@ -0,0 +1,108 @@ +package com.bytecat.algui.AlguiManager; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/24 17:07 + * @Describe Algui资源 + */ +public class AlguiAssets { + + public static final String TAG = "AlguiAssets"; + + //纹理 base64 + public static class Icon { + //圆 + public static final String round = "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"; + + //X + public static final String fork = "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"; + + //✓ + public static final String hook = "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"; + + //默认图片 + public static final String image_def = "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"; + + //错误图片 + public static final String image_fail = "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"; + + //通知纹理------ + + //信息 + public static final String inform_info="iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAByBJREFUeF7tnc+O1EYQxtsz3COQwiMEKTzCRlokrpBb/ohzNnkApHDbAzeQeIAA54gkt5ArUkbKPgKRyCMQCcSdHaP2jmdnPG27utzd7q+6fNnVru2x+/v1V9XVPXZljFka3YptgUoBKFb75sYVgLL1VwAK118+AJ/9+sOxFXm5qJqfdqsrs/29/VtVm1UXhvN1vfpw7/nB3yVBIyYEtEIvltXpRXC7FDyIYHW9aiF59/2zh0HOmcFJYAGILjhBnGpdNyAgAwEHgBW+6eWhezhB8MFdNg6BBgMEANmK3kMEkjNkDQCa8C4eLAw5u0KWAFx7cXJaLzbJ3FRrzuT4XEHICgCJwnf5yw2ELACQYPW+RpMLCLMCUKLwu6DkAMFsAJRg91RXmBOEWQC4+tvJq+zG8VS1Iu03FwRJASjd8insrD+ub6ecf0gGgFo+Rf6LfVK6QRIAVHy6+NvZyUQFpOgAaLz3Fz8lBFEBUPH54m+PrOvV+++e3Q5wJucpogGg4geULCIEUQBQ8QOK354qEgTBAVDxI4gfEYKgAGi2H1H8SBAEAwBN/K8+/8IcXb9hzt6+aZr2n///S6BemI8IWScIAgCS+A9u3jUPvrzjVMJC8Pj1SwgYQkEwGYCmvHtl8SoM2/HOMiR891Mf/fuXefT6ZbyLCXTmEGXjyQBc/f3Hj4HuJ9ppfMRvLwICggAjg0kAIFi/jfV/3rrPguvaHz+xjkt60EQI2AAgiG+FsOJbCDgbhAtMnDxiA4Bg/Vb0d9/8wtF+ewyECxhjuPkACwCU3j/F/qFyAXuxzFDgDQCK+LZNOMkf6ojAXjfHBbwBQLH+EgHguIAXAEi9v0gAGAmhFwBIvb9UAOx9v//26RVq5ksGAK33lwyAT5mYDABa77cAhBgFfP33E4i5gW6Pp7oACQDE3t82yJQ6gJ0csgAgbtQRAQkAxN7fijZlKIja+5t7J9YFRgFA7v1TIEDu/e19U1ygCAB85wRQ5gBGQxPBBUYBQLb/bgNRwoEY8Tc3P5YMDgIgwf5dvcSODn6+eXf7r7PNcjCERSCjvb6zw1gYGARAV/j6NneG+4+EgWEAAFb7ZNjk2V3SkAv0AiDV/rNTJ8EFKQAJGjnrjxgIA70OICn7z1qcFBenAKRo5bw/oy8MOB1Aevy39QC7He0sFkX5QggXMwWAuERMWiFoC0xPGHA6gMTxP6UK2DaWhHmAA6fwAkDY+J/z3QCJTuAqC7sdQBAAUxaFSIOABADKlz2pyRCn9++eG+WLIZT2cCWCBw4gaQQwpfe3DQq9KIQwMaQAjHQdSWHAtVhUNAA+mX8fBwoAJbhkuo8CsC+MOgADVEkO4FooehACJBWB1AE6xDuKQQpAQUmgOoCGgIPnDqsDqAOY5W4baA6wT4SkJFBHAYWHAAVAATh4ja1WAgvKAUgOIGk2UOsAjEqgAiA3CSRNB9vbl7IkXB1gH2bSghAFQK4D0AEQ8mpXdYAdmL0WhSoA25aTUgjqe3KYc1GolERQHeDSARQARhHIHiLFAfqeFNL/5VABYUAd4JJ6BaBgBxh6cmivA0jIA9QBLqhXAJi9X0oOMPSkMNEPiVIHGH9i6CAA6GFAARi2/yY8GLO/IqjrlsjzAgrA+LsDxgEAHg6WDgDlvQGjACCHAQWgPlgB1HX4UQCa2UFQFygdgLHnBJNyALsTqguUDADF/skAoK4RKBkASu/3AgDxwRGlAkDt/V4AILpAqQBQe783AGguUCIAPr3fGwC0EUGJAPj0fhYASCOC0gDw7f0sAJBcIAQAKE8J44jPBgDJBaa8ONI2EMpzAn2tv60IkiqBrul0lIRwigugPDOY2/vZDtACgVIi5roAgv1PEX8yACj5AMcFUFYDc61/cghoT4CSD/hAgCL+2DsBKSvh2DnA7slR8oH2hZH2p2tDEb6x7vX4VG8yAJps+cXJab2oTikfmsM+LQRH12+Ys7dvjE34ULZQ4gfJAXYbDSUpRBHadZ0hxQ8OAEpSCAsA4W3gvvcWJAfofqg6ga8MhP0jiB/FAdBqBISmn3+XSOJHBUDDQSBuIoofHQDE0UEg2cKcJrL4SQBQCHgshM72+64iShLo+jC0OgFPtjBHpRI/mQO0zYJSNg4jI+Msdb1an9cPP9x7vmIczTokmQPsXp26gUOrBPHeRcgsAGhesC9FSsvvQjAbAO2FFO0GM1h+dgAU6QYZCN+CMLsDlJYbzGn3WeUAQymrxLCQm/BZOkAXCngQMrL62QtBrEHq5iALgv0VZsEJgPAQDtBbUazMsamq4ylQBT8WSPTde88qCfQVZVZnqOumWmcrd/ZnyuqdbzsN7Q8NgCtnaEJFDIcQIniWdYCQRHfPZecflovDcNFA0tmq2mxr8Ofrix6O2rOpbSrKAag3rftdtoACUDgNCoACMPyo2MLbR/ztfwJILipM+Dn3VAAAAABJRU5ErkJggg=="; + //信息2 + public static final String inform_info2="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"; + + //成功 + public static final String inform_success="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"; + //成功2 + public static final String inform_success2="iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABFpJREFUeF7tnWF22yAQBsXNmpO1OVlzM/rkWi+ua2tZWAnQN/4ZI8TujFZAIiUtfKQzkKSjJ/gFAcQlQAAEEM+AePhUAAQQz4B4+FQABBDPgHj4VAAEEM+AePhUAAQQz4B4+FQABBDPgHj4VAAEEM+AePhUAAQQz4B4+FQABBDPgHj4VAAEEM+AePhUAAQQz4B4+FQABBDPwMTh55x/rMNPKX3VhkEFqM1cx+Nyzr+WZfn5NITPlNL6c9cHAVzp6t845/x7WZbblf/i85VS+vCMEgE82erc1oC/jc5VCRCgM9TS0xfCv3WXUirmWtywdKC0i8+AB/797B+lE0MEiOcV2mMF/PX8CBBKoVNnlfC5BXTiFXraWvjLsrhWAtwCQrHFdNYA33X13yaMMUOml6gMtMD33Pu38SJAFLmAfs6GTwUIgBbRxX1Pf93hq/0Uz/qfT0AFqE150HE94VMBgiDWdtMbPgLUkgs4bgT4CBAAsqaLUeAjQA29xmNGgo8AjTC9h48GHwG8BBvajwgfARqAeg4dFT4CeChWth0ZPgJUQi09bHT4CFBKsqLdDPARoAJsySGzwEeAEprONjPBRwAnXKv5bPARwCLq+H5G+AjgALzXdFb4CBAgwMzwEaBRgNnhI0CDAFeA3yzA9nz6raOGZ9QbOHQ59CrwqwV483y664GELuQCTnol+FUC5Jyzkcfqv1AN4HNoF1eD7xbA8Xfrl5PgivBrBLCu/scr8DISXBW+S4DKJEwvQWXc01wIxQ+GNCRiWgkaYt4EGD72YgHWiAomgO8mYcMn4nngCvBdt4C7AK9eT1Y6855GAhX4bgHuEuy9psySYXgJlOBXCXBlCdTgVwtwRQkU4TcJcCUJVOE3C3AFCZThhwgwswTq8MMEmFEC4P9dsLk2gqw1nuOXRa+6Om2JCPzv9IcKMEMlAP6/1164ACNLAPz/C+8hAowoAfBf38APE2AkCYD/fvZ2qAAjSAD8/an74QL0lAD41roteBm4d7qzl4jAt+GH7wNYpzxLAuBbJA7cB7BOfbQEwLcInLAPYA3hKAmAb2X+xH0AayjREgDfyniHfQBrSFESAN/KdMd9AGtorRLc++/yzxas2Gb4/pR9ACsRjRJY3e99f9pvIFsGeeSxQwgQsFlUkyN5+KfvA1iUTqwEwL/DGKYCbHKcIAHwH67E4QQ4+HYA/KcyPKQAB0kA/Bf34GEFCJYA+G8mYEMLECQB8Hdm38ML0CgB8I2l1xQCVEoAfGvdHf1cQMH5mpo4lojAL8z0NBXAsU8A/EL4w+0Elo77zYsqP1NK6xtM+DgyMF0FeIxte1Wt0mtqHWyLmk4tQFGENNrNAAKIC4IACCCeAfHwqQAIIJ4B8fCpAAggngHx8KkACCCeAfHwqQAIIJ4B8fCpAAggngHx8KkACCCeAfHwqQAIIJ4B8fCpAAggngHx8KkACCCeAfHwqQAIIJ4B8fCpAAggngHx8P8A2akIn8YbW/UAAAAASUVORK5CYII="; + + //错误 + public static final String inform_mistake="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"; + //错误2 + public static final String inform_mistake2="iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAA+pJREFUeF7t3VtSwkAQBdDMznBl6spkZ7FiJVUUJTAkk+6+D370IyTTfQ/NoKBt8k26A026ehc/GYA4AgMwAPEOiJfvCWAA4h0QL98TwADEOyBevieAAYh3QLx8TwADEO+AePmeAAYg3gHx8j0BDEC8A+LlewIYgHgHxMv3BDAA8Q6Il+8JYADiHRAv3xPAAMQ7IF6+J4ABiHdAvPz0CTDP89c0TdfW2lUpi3meL9M0XVprS/1pt1QAa/ifa/UfKgjW8H/Wur8zEaQBuAt/ewTQI7gLf6s7DUEKgAfh0yN4EH4qgnAAL8KnRfAi/DQEoQA6w6dD0Bl+CoJoAMvOd9v89Ox84fcEb4a/9CS05lAAS3XVG9KjsvcYhFrDAaggQAh/ySIFADsClPBTAbAiQAo/HQAbArTwSwBgQYAYfhkA6AhQwy8FABUBcvjlAKAhQA+/JAAUBAzhlwVQHQFL+KUBVEXAFH55ANUQsIUPAaAKAsbwYQBkI2ANHwpAFgLm8OEARCNgDx8SQBQChfBhAZyNQCV8aABnIVAKHx7AaARq4VMAGIVAMXwaAEcRqIZPBWAvguV+ap9VWGv++5L2ruDbRYz8fsej+Z3Lh35o452F7T2WDsDOSdDTP7rwKSfAluTgSUAZPjWAgZOANnx6AAMQUIcvAeAAAvrwDeD51s8AerbG1Y85uBmkR0D5MnDwKwFqBLQADj7y7wcbLQJKAIPD3zBQIqADcFL4tAioAOwI/8O/DKq+je9c357wtz9Ne+S+ncsrexjFBBgR4IhzlE35ycLgAYwMbuS5UDBAAzgjsDPOWRkDLIAzgzrz3NUwQAKICCjiGhUwwAGIDCbyWlkYoABkBJJxzUgMMAAyg8i89tkYIABUCKDCGs7AUB5ApcZXWssoDKUBVGx4xTUdwVAWQOVGV17buxhKAkBoMMIaezCUA4DUWKS1PsJQCgBiQxHXfIuhDADkRiKvvQQA5AYeeAdyifcYpgNgCB8ZQSoApvBREaQBYAwfEUEKAObw0RCEA1AIHwlBKACl8FEQRAP4mqbps+dHlNH/RbtzTbsOexP+d2tt6VPILRTAUtE8zz0ISrxGHplAJ4LQ8Jf6wgF0IKALv/PpIDz8NABPENCG/wJBSvipAP5BQB/+AwRp4acDuEFw3T6oOfJ5t/K51j3BJXLD918/UvYAlYNRW5sBqCV+V68BGIB4B8TL9wQwAPEOiJfvCWAA4h0QL98TwADEOyBevieAAYh3QLx8TwADEO+AePmeAAYg3gHx8j0BDEC8A+LlewIYgHgHxMv3BDAA8Q6Il+8JYADiHRAv3xPAAMQ7IF6+J4A4gF8nwp6fTforwgAAAABJRU5ErkJggg=="; + + //警告 + public static final String inform_alert="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"; + //警告2 + public static final String inform_alert2="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"; + + //面具 + public static final String magisk="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"; + //终端 + public static final String terminal="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"; + //猫头鹰 + public static final String owl="iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAYAAAA8AXHiAAAAAXNSR0IArs4c6QAAIABJREFUeF7lfQeYHNWV7qnuCdIojXJESEhGEYwQCpg0gDHIBgtJyIC9XnDCG4yf3+773reYIIHXCyY573q9Zg1ek6Mfa7MgjARIKIA0ijMSozDSZM1ocp7ursc59557T1VXdffMSELC/TG0uru6u7rqr//85z/n3uvAX/ht167iAnUIEgUJAHDAvYweuS6A6xa4rgvqn67aKoFb8WN3HW7nxuHtBKjn6fUErLvkkgvX/SUfWucv5ccXl5QoACUSBY4TucxNIFAscAAkgOy/GVAKYOqPgSWfswBMGCDicwk3cS9iDoF3+WWXrP5LOd6faGCVEJicVS6AZiXLPF6AEFQEMzGIDDN5wKK29YLPCzJ8HwPMCzQLtgRceeXln1igfaKAdejQoYIYAEQBVrmuAhMDSNMMKL7xAkyRUBAjSWAlA8kfGpMZzH4mAxFDpdwuAe66RNx9OwGxdUuuuuoTEz5Pe2AhmBIABRFwLiNmQpQ4CAiDIAUkH6CSwSVDnBdoVmP1hql422TG8gBLA420mutCPJ649wtLrjrtmey0BdahQ2UFThRWocBmNgLH8TKUh7FQgScDTIZEr3ZKBhe+O6G0mQiFqYHjZzF8fxCzMZMRwBIJ0maYB1z3hatPS5CdVsA6VFZWEElAgROByzjUMTXh6cYfw8wkn/eERDxxrKD53+K51CLdHxrTMZgFIgMyCVjIWDqbJP3lYzB8nEi49y69bslpBbDTBlhlZWWrwYkgQ3kSK+8joqjQ0IevBWksf1iUj1MxFDOYzRYVkCw4WcT7Gc4LuMDQyAAj9tLvjyfuXbr0C6cFwE55YJWVVaz+yFxahSfbw0iCdSTSAhkrAFAWgEqUS3GfbClQ8CPQhmd/YSFOhU7LWN5sMUnMBzCWh8k0g61Ydt0pDbBTFlgVFQgozVCOVuP+ex36UoVAyVLm371kLulfeRnMr7n8oU8ZpsGaKo3WEoylLAqtvSSDuXDvqQqwUw5YZVVVBVnCLkhnKHoYyi/e0+gpZiCTNdL2lsGSDVHpT1kmCg+FyeCxoVIxl3LyvSE0gR6YDqmksYygFxpMVwBU2D71AHZKAauqqnotoGWAzCRCHzNSRqHQdeHg0VYT3j6sboYPq1roBGJCF9cnDO/xhJ09bgiBiU/4zAlDdVRMwJxJw3zGqBLvyRoqyBC1wAljLC+gvNszuCSoVLbIWaPafxPSTzFwnRLAqqqqQod8rQRUIFNxKBQvIm+U1rbBoaOtBKj91c0EIARSnO8TLgEKT0Q8rk4OPqa/OG6H9+r1GL5O2yJrJGD2pKEwZ+IwmHNGPsyZlJ9U0pHZnp95UtkK/Jo/SwzSXGGMxSFSnsRThb0+VmAhoBwnuspxbMlFUVUyYxmtrpnscF0bvLP3KAGKgcKAwpOFYCGA6H8rQIEFEr+GACSQ6fs4gw4ZRIEL79UJT8BNn5lK/77pommazaSG8meB/izRsp03JCZvZ2wHKeZJuCeHRv9FeCqA62MDVlVNzeoIOJTthTKVFOsAUF7fDhv21QKCCsHEwDH/1kxkgKYBo0KgYiLDVJ7HDC4/g2lAaVBRKKJ/xyERj0MiEYebL54ON19ytgmPoX6VDqHJjOR16EOzRA2oJMBp4AUx/McJsI8FWDU1tas/0tmrkgClgeRoxuKDteXAMdhYUmdCHDGTzpT84CIAMZBEiKNQKJlJP45pgJl7X0jEz5PM5SbiuvQSA/x3PB6newTXVy6bqYFnmSu10x60nWJAfl+SIx8i5ski8UsFTGYS7seSOZ50YB2trV0LukBsAOQ45FHJW1VjB1Q2dsKW/RpQEkjMVuKegeMJg0GaKiwESs0lAIiAowxNA0rd65CUQOaKEXMxg3350hnwVwWzhVFqgRKkwSRDKTB5geV342l7CS5hP3B269Fc6smTDq6TBqza2lpqYcGsTwKKsz8VER1yxreXNsAHh+rVlUt/KMZ1kVaLcCWwdTgMCIFKvLuQQM3Er3NoTLgQ8zEWaywW7/g6gnXWhKGw80i90VikuTgkImMlvMwVj6vHX7lsNvzV5XN8Try1C5LFux9QIcwVEBIlOFPZM44Lly9bdt1J6aA4KcDSoForQ1zQv2uaOmH74Qaoauz0hDryezSIECTIIFacy9Dn1VJJWsunsVi0Tx83lADwxQsmKYfcdWHmxGF0Tyk9F7PF412Hj9FrO0vr6ALYcagGth+s0cwVMwz2VwVz4KtXnNNngHkZjTWeBagK1fZxWt/vJLHXCQdWbS3qqQjpKf4yBpUE15/3HIXqpg5dFxMMpYHEzMUHUtkHylZgUe4FkrYXAkT7WWOGwDXnTaCsbvq4IapUo51GYhIBJM9jfF4XjUnTsKelt1cAOwo7Dh6FwoNVsH1/FTEahslHvnkVnDt1XJITHy7WraiXOk39XpEZ+hiMy1EmKZK1Va3BToaoP6HAqq09ZkQ6flEQS9W2dMG6oqMWUCb8KQecDU0OfexHyVBo9BWFPD/QbMY3dfRguOrcCTBt7BCvHyVBJVuPQwDmdeSD2masKH/izR1QeKAKtpWUw19fcS789WfP87BXGLCsgE8OiUm+lgAXvubXWEGPTzS4ThiwEFSRiLIT/AzFj/dWtUBRRZMqbehWX5MNGW2lQp0JhTrrs046G5raBDXhzhqhl88ZD1fOHR8KJhPq7CAKO3iCmUmwUhBTMVOoEo116CVwfvvGNmKvW646P5S5wvytIJtBHRMRCsmLU9+fye1EguuEAItBFRTyGGjvlRyDupYuBSgKMS6Nc/ECy4pzxVBWQ1mgWRHPmolD4uSRg+DWgun6RKtDLTsXJAD8odDTyZCOuUSN0e+2BwHlt69/QJnkrZ+7wAOwoKzQAlNlpwwmf1HaD7xMgKWJ+oRkjMcdWMeOYfiLhDCVKm1tOdhAoFINblbTqIOltVOIveAJhSEG6BkjB8FFM8fAmaMGm+PrB5QElfl3mLaSWsqnsaS4DyrhpMv+0mms4BKPBpkxbBVzSQYL87U8/WwnUHMdV2AhqNBSQKYK0lON7T1QUtMG9a3IVMpg4RB48fr7yOBzHdWzTq86ADXDZnxkwzhQOXQG/bEBKkU7Z4gIugvPHg0XzRgjjh9ndV7GYsRxIVcCT2oo+TqLevN6gHiX4OKsUj5nmUWJ83TAyt61G7J374Honj2UCcdQR9KfqoV2z5wBsZkzITZzRjKwRFsR/17utPU/Pt5h8bgBy89UfmA1tPfAttJGVfowGsRqq7P3Pg+zSl4kMDkRXRDEK4qAhvfquW0TvwiVg2dA+aCzdfHY2g2Lpo8mYGmKF9HA2wojw4RXiOtMTH+AAYTfbghhMD9j4cf0RZwP2LUHhj77PAEK/bQYIKCUL4fA4j983L5iGXQvX2ZDpNBcmYZD3u54+lzHBVi1tQ0F0SiE+lRNHTHYfqTJAygGmAqFeOUCzPjweZix/0ULrEgysOggOABbx30Rtoy5zmSB1y88EyaNyMuAqYIZzIhvv43gE+PeC8Pbb2V9LxXSlXb097TL2mBy6WbcPathwM49JBEIUBjuNbBiLhDAGFjtK5ZD5woLKjZuOST2Flh0aI+TiXpcgFVf3+DK8KdKffaj15fUe0GVxFg2JF64+T4Y1VhEb3ciKjQS+2nGYmDxx78/+joYf83fw4QRA31M5QUQD0jl4RZs74SKeR5SHwA06XNxqPTfc8OgNwwml2yY0YY+9wwMe+55RA4OmwY3LtgJlI2CYyYZWG03LAcEll9bUWmJQ6yfugNqiX7N5bjuumXXX3d5X0Ap39NvYGEIjESiHrFOsNKF5D2VLYCMpQ6wTsMDQqHSWi4MP7YHPrP1BwAmHOpSD2KLwWWcViUi3EW3grvwaymBZY1D0eMekCU6pYVqP8GFyKHtxDz0HeI+NuVcVYieeq5ptksClsl2FWNZEe/1pbL37IShLzwLubt2A8QRUOR5AKJIhj7UVMxgeN+6Yjm035AGWHofMvG1pOaKAPQbXP0C1rFjDeRVBdkK+NzeqlYFKh6+LgDFQGNAsYgnAb7tPhjZpFiL/igk6uK97bKRpAjuxPPAXfrT0FDoZywo207HMrLhcQKOc7hQMQV5HvrkauZw5PPUPagYRd0DASw2ZS6Bp/uscyA27RyrJUUWKcU62xAj//kuyN2NoKLJReheAQzDKTIUM5fVWM03LIe2lSt01cH6WMaKENmivaB6x0H9FfN9BhaDSrKTBRhAZVM3dSdYTaLYRflWlr3YbmCfCjs3RzQUweLt9wnWEsBi5tLRVmY57oR5kLj2J54jKJnKqdgOzmYFJAQW5gUEEPI9NFACgKWAhiddMxezinxMz1nAdXzuy8Ry7Z//sndIvRhcMeKHd0HO7l32fRpYEmBhwGpduYI6IbCBkQFrQqAs+/iGy/UGXv0BV5+B1dDQSLoqCFg1LQiqLh2auA6nwgszUxJj4Yws2rvKb9gDi3bcJ7JDmSVa+UaSwd8bf/6t4M7/mmWuikJwtj4OTkWhDmkq0eTQhmAJBBYzkgYcbYeCXANI9T1rIDHTaAYz2+nn25cokLVde7M2gBMw/P47IWfPLgVs2k5/PgopArF6HhlcgUsxVo/rQtVzTymwUjEe+8F8PpYAFlcC9IkiI3FPaTXMmTIusH8rSXMl3D51RPQJWDYEWpGuxLu6HnZWtOlxeFoqa6ai9FtqrYC2GC42L9hxL4xsKVL2gwyJ/JVyz/0iYt6tdHycqu0AlRpQ+JgAFQAkKkrq5w2gxAkWTGQBZV83DBMINAGcuAutX7iZADro5adNyOPQpwBmQyE/r+wG9dc+exbUrbpL94R5SzpBjOUBlv6JRaXVdJ4QXGG+lmC2dcv7IOZ7DaxkXaXONAPr0LFOaOvGI8x+FaUmWrgzsLQ5aGqEPG5OCVa8GufvvBdGtGidpYW8yg61r+VNPO1xMINP1VN4NROg1GgtFfLoXocuZiT/Y6GhjObS2scwCjMUs04KYFlmYuBIhlJinRhQZ4UGYDFliBKwwIW2WTOhbvXdvQJWkM569u3tcONl52UUGftiQfQaWGHWAp70Y+0xqG3pVidU77LNBpNDoWzgY6bi4vL5u1YHAstjP/Bh8TMW7wDPxMdAygRYGlBGcwk9FRz6NCN5QGW1lrQPUjETs5VXwCsGI09LA6v+huXQrPUV1xZVe7Yo6fhCYRCwMBzuPlydMbiWX39dr7DSq40bGhpEyYaZyt6X1GL9L9mADHLaSXCa3m5fD7vrwpQjz8FZFS/orFAJKfK1sMCDWaJmrCQq1xUhCoUSWIal2D7wZX9GoHuzPm/os2GNNJo/dPnAZTM9HeKCGMkX+pJCYcxmh8hc9SuXQ5MElq9lxrQuy+e548HnYy2/97fw0ipl06jjKed/8j52emlBZAys1FmgAw0dcWhoR7LWIYhYQ4fAFIao6avyDY44s+w5OKvyBWWQarvBelsWWJLL8VldgtSxz7GhTwPLiHYOfZwVekKfApdhGBbTfuAEhT5hcAZpJj9rSYZKxWhsjNavXEHACm2jkQapNkqlzpIX4j1PvAZzpoz3sFYqzdWbkJgxsFJlgU2dCWjoQJFgTq05wdJusCOOrdZSjXz4WPddEY0DTC57FqZUPW+YShqmqnYoDoEnFOrnlcupAMIai/0pfF4DymR5bDdwKJT2gSfrE+JaZG+BAAnRTDLrY01ltBUeRuFp8edSSxC4cOyGFdD0JTRGvUVsLsrTwA7Zp6WBFhYO737iNfjBLUtUlpjm1hvWyghY/iyQSzZsNxxp6vHm/YEaSwVJY4iSvlfClO7lYImEC+cUr4L81j3ay3Lo3jrvvhKPPCBW3BlAkcHpD4VxF1IZnx7PyuNXJQMrSBexhZAs2r1ZX1AW6GE6zYA4KITE++xZULP6ruMCLDxsyFp4u++WJelwpbRzhj3zGQEL2UqFYLYUbBbY3OVCc5ftWlRXhmIuW1NTEUm2yairysdUupEPLYE5xfdAftse67wjsCIav1ycJuHlOx7EVFYr+O2FpGyQ/SMd+lQ3oRDf2gH3iuu+aCbNRJT9+bJA4WUxEP2A5NFGrQisexlYqnvWGKR+0a47Svn1IA2151AVGNaaOl7MsRmuuTIR8mmBFVQLlACrbIkb/0ojWiGbtZavRmi6GbRJmTzqRon6C7csByeKRWjdRoOWA2st7Wup4WLYrcUhWEwVaeyFIANUa6gwfyog9BkRn6ShgkJXsh8Vykz8eXjPgA7ws/A1zAxbZ8+EamE3qDGOqrhtskOfcOdxiHxe/En0int/C3OnjCPWSudraX5I23WaFljSXvA77W09AK3oWcmRy74Z9VRxlks5ugVZZ2vstCcNjHBdWPz+cgUkzVSksXzAUt/LvpYCGDEmg0rYC6YGaOwEbwmGa38WAJpZtCseyCRSQ0mAIPvFtLvv00xe8PicewRWCoCRn5VwofSFpwPFu5IUdtyjv3YYFuswHO4urc5Ya+HnpGOtlMDi5j1uibHaSuX6RzuU+ZgUjlQsDu+/4onEPIMk7HCt8WXPwKTqZw2wLLh06JONgP6iTobA8gDNb3yKx5lmbUFF5EAGYgM0RKSbkCsNU81gXN6puvcu6Jg1y9OBylliX4CFZumz6wrhxoJ5Gfta6bRWSmAlm6FWY3XEHWjHH29CkbAZ2GpI0R6jxoUGj2QeX/Y0TKh+lkKhYir1p/qzfB2mgrEI4UrM2WwwE2ddZIIebZPSd7LhjkAVAIRU1oLNApO7GghcASESL4YeNwFoOTSSl+Uv6SQg4S9KZ9CfhWYp6qy5U8bDfbdcY4ktTf9WKvshFFiSraxwt0XnzjgAgotv/C9vUiZ6sDzhzzcaR4xsxqvy/C1LFVtFNaAMwBRjRUbPA2fkPPXVI9S9M2IeuPWFZn/cY4Xg1hWCW7vNlG9SFZFtKJSaKbh2F+xPaYAkhUQGDkDW7AsgOmcBROcuYDoXYhQgtvV9ujB6tmyBnk2bbYmHux7wNSxmz5GZYYCAZ8CxeBfzO4RpKDRLOTtEvcW3VJorFWulAFa9G4kgVXA2KDNCgIbuiGlF98ZC67yT1NEtutZmsKNwpM3Ak3kMbNwJ0/feBQ6CSgAqOuvrytP61NfDpELo8wiyRPFj4B4ttF0EsktBhj4TqrQDL0MX/had1dF9SNFYPh85+wLIXfE3BKje3jp/+Qs6fh0/+bnpgsDuBhTx1avvgs7Zs4KNUl92yKOnU/Vmsc5iEZ/JvqbytQKBxeMCJbAswAC6EhHoStiROOZDeDiR1lh+e4GMUE6P9YBUpQnQE1QG6ZRdd8Dgtt3EVhgKI7O/QWEwcnbvAeU/OMhg8aLHwK3epgEWIJ5N6p/cZeAFEtsHOsP0aabopy6AnOv/FqKzLsjkHKXcpuNnPyf2an/kZxQKudOh/PlkEZ+ksXxOfNgXcTjE1zM1TAkTIT3ygcAKF+1q845EFBK6o4E0lsgKZS85MxY25yJ4OAu0TKUHoGrAjTz8JIwuf0ppqyhAdM43wJnZf0AlAay2EBK7FcCM8y3YR2ojztL8dkFQTQ/fF50+H7Kv/RuIzug/oPz73fHjn0PzIz81Lcrtc7CF5s5kL8sfCrm0o/v3rX7x1gY5HBrW6kePfAiw6n2DI1QYRADF3Qh0ulHzWFtKOhpaH8nbyJdcZDYdo3rI/PCD/wWjyp6i8OeMOx+yCn7R7ys93QcguGLbfxMY0mTbimln8YS+ZMaKTpsPA/73b9J9bb9fb3n0p1D/8E+IuRpvWA7YTSprh3LiEPNv7lz1JfH+2uHu0iragovTmfhakQDWSgKWHB5vbQYr2nvcCMScKEREY5/xtzgLZLshwFbgjgZuk+FJPKa/tQScLAci534DInO+0e+Dn+kHJHY9BvFCBS6yIHw+kszeQu2DOED21d+G7CXfzvRr+71d0yM/hWOP/AR6EgmoX30XdJH94GtVDtBaqb64r+EwSMQnAauu7phhK2mIMsg63CyIRJS+QnBRnDX/sxUByVgWTHraIZ5+SJdwxr3/f2Fg806InvdNiMw9eaDig5zY+RjEtiG4tDgXOsv4WIG+kwJi9lXfhuxrTh6oeL8bHvkJHH3ox9AxexY0rsIyj53iiNtnjObS4TBTYPVXxHuAhROkfbT66FoU7d5xgpaxupwcw1YGWFa9e1qSpU/lZShdI0wADNn3BOQf+j04E+ZD1mdPfPgLO7CJHY9BfOtvwp3vEEc864rbIPtzJx9U/DuQtWoeehRacDiYGLkjG/9kVujJDAM01PLV/2kO0Q9u/TzMOXOsPWSp+rV84dAPLJrQIygEkr5ysiCBYZAYS9sQMmaLlSFkKQf/ze0xZv4q14XBRU/A0P3/BZGJ8yHr6l/2Ozz09wMwJMbeV8zlccBlM56wG6Jnzofcb/+6v1/b7/eXLrsRmjZsADOINcTHIhZLobFwR9AoxZDI2eHsKeMymm/Lnx16gVVXv9YBt8CJRDQrWabCL0pEsugPmYrKdnqWPm9WKOZm0LPJyFDIwMLnxr38Wcr+spf8kgT7qXDr/o/FSm9phgrL/vD5gT/ceirsMrS9txEOLPsSifmmu++E2Cw1e3Nfxhmyn4U/rD/h0MdYdR595a8R9kRzNagUY7GATwKWGPHsmdeK5xFNuJC3+3EY/OHvIDLxfMha8q+nxAnCncBwGNvyH2ZIVhjAsi67DbKvvO2U2W8Mh+UPPgJds2dC691Kb/nncvCP2Anaea4b8mue1uU0v1YWpg2wcO71SDSyCp8I0liuE4F4VOkrZisGFmst/F7uGPUORLUrRPB8oaOfvZyywOi1v4TIKcJWfNy6f7WYRLl/ZLJksoH3fXDKgIp3ZNuYSWSgtt19J/TMnJmesQI0E/dn8Wd6zNJe1A69wNLD5YM0FoZAN5KtOllEViiZi8KlaTXmqbTtXKKkteIJGLDzt5BX9AREJ82HrGtPHbbigxn/4DcQ2/gfaoCqzgaN1RADyL7sNsi6/NRhK97vqocehSM/epimNupasZwYy58VptNY2D7DXaX4uXPOHAc/uNV2l6bsiRcDLgywjh6tTQqDsqSDwh2iWcZmMAAjhlPWA7U/6ekM1Sgc7+zHzFYjfn8ZGaFZS/8VIuOPr7Y6VHrYMAn+e3h+Pj3Ozx9Gf/w4Hd10/WKRCocBzDVw1fFlq4bGRmhsbKJd4vu+7HPLho1QtHQFOfOtT/1eMZYo6WQSCvF72YHvrc6i9+phYpaxjta6FNK0P+W3G2KRHHAiaIxmwFiCubAGyLMf4w/N2foYDNz9BETOOB+yl/5buvOb8esIIgmqsDcisKZMmZwWYD0v/S0kjmz1MBYKdueM+ZB7679nvF/pNsxkvzPdZ/yuoqU3QP36DTRvVs/yZUmNf+n2B1+XAh4f96V2SMCqqalJshnIABXdDV2RXIgSM7FoVyzFoZB3OJ3GGvbYpYDkFzljPjFWf294YvAqx6u+N7d0Jyu+5TcQe+8/kpz4rEu+BVkF/Q+DmQDK/3twn+edd27Kn1mMwNqwgeZ46Hjyv7zZYZpaIffE+wW8AVYmtUM91wMBq6qqxkxHJPVVErAIbMmAMuKdappiJhnDXMrHyvngMcjd/jgVmbNX/BtlhP25IZgKt+8M/Yh9e/fSazNmzgzcJtWJSpRvhZ7n/ta0q3ADYO5f/ztEpszvz24Ts4axK+7zh3uL4eyZswL3e+qUMwH/wm7NG96DnV9cTtZD13LFWh6DNI2PhXLmOd1Ryt8hbYd0Go3LOx5gMZD8WaHrRKHHyTagYoOUGMu3MIAdR8jjBe2I56H/folq3jtOwEJQ+ZkKT8x/v/IyMKj44Fx3/fVw3fXLks5HqhPV9ehCT2aImivnq7+CyNS+AyvoYkCA/+7x38Krr7yStH94UVx7/TIPyFLtMwELdRbNAOhC5+//y2M7ZHJFyJohbt8XP4uAVV1dE+JfqZpgzMmCGER1KFSsld55V5VoHjeYtekxGFD4uGoxRlN05a/6xVhBV31PZwdcfc3VdOy+ctPNsHnTJs9xxJP0j/90R8bg6npkoW2r0Q1//RXu/oth6OBBcMEF8+FnP/kp/Own3rm95I769x1DYlgi8u7IcaZnq/vOOyCO1kOKdQ39B8QPLHw9Uz+Lm/9SAosZjIHFYVAao4qxeNdE24yeYYYHouZsfgwGbHvcMFbu9zZncvGEbvPWuneSXtu9vRC++73/Rc+HnaggcIWFxK6HkbG80xANWN33jDCIra4ouNT8jqCLQf5IybqpWOvdkePVXKXgkp8V+/4dClj4YQFr65jv0BoqCFiks3ox7tDh9ZhJW2HxGYGi7xlYPaAYS4ZABS47JxZji3veeR4s7hgd+ouLTQMfhsIB/7Clz8AKOkGvvvIy3HTTjbBo8eKUwMIXkbX8ukueYN6x7mf+BuKHttraYQJg4L3HD1iPPHA//PF/1EjkVBeDPFC876n04TvIWDoU4nCxnt//joBFuMpAY+H8WVgzVG9Qw+tYwGfyfuzPcioqqlZHIlh49gJKinhslUkA1w+13aD9K/xus66XFu+8PzyjTLSsEAa//F2ALDU2EENh7j/2HVhBYRBPUn5+Pjz5zNNpT1KQ3goKLV0PilComas/jrs/DN526y20v3wxTJ8yNe3FJvc96GLADyBgiblLY3d+HxIzZpjlXtJ+ic/Lwu17MzQMC9IELEc77kE+FgKsPYHAYm1ls0IuQvOO0shkz7JsqnN0wMb/hAEf/NYO54o6kHPTv5Hl0JdbkGjHk4S3737ve6St/PpKfk9QOAwKLZ0PLEgKhTlf/zVEz+r/fmNygRcD3hBYqfY3bN+DLoamDe/BdswKBWNRUfqOf+rVoZYmKb6xNwIeM0PNWHaZEslU/O+muC7l6NDHz9tpqnQg9DOWthuGvPBdyKkqNKNuyG64ue/ACmIsBlYmRy8TxkJztPvJv4Fyd4yYtNaFabf8M0T6CCy53xJYmezLbVcgAAAgAElEQVQzbyMviiDGMsDSgy7QzyLxjsDKwIdiDRYIrFs/n5FGI2CVVVSsjvp6sPzgaoypVhnWVEa860k5ZItE0JwNo35yqQKVGCeYdeltkPWZb/XmmJptgzQWXv1+iyHsw4OAJU/Sps1bwGmphm0Hqs1AEdQouLB4T08PjB83Di68cDFMOTPcTwr6bv8F0ZuLgT+P9z1MYx158GE4+MBDZJCqyXDVqB73+3eAg+3LGWgsPJ9+YOH3Y2aYyftxnninvLJq7Uf/oHWaw/4aerBGaB13aTWQxpJzN4g53XEvBm74Txi0RWWDZmRzFCAy9QIKh329+bPC/gCLT1JFRSVU11TDzl27IRrFZEV10qrRRgpYsVgMuru7oaurC8aOGUMAmzplSkY/w39BYMIR5F2l+rB04h3N0WPrN5ipJTkkuncoYGV6CwNWJu9Hy8EpL69c6zgaWJwVMsj04/puDSwU3mI6IynaCWCeWWbUREaDNvwWBiOwcOyrHoDKABtwx/uZ7GfgNn0Nh0Fshfqqrq4Odu/ZA9nZ2fSHwMI/vrF7jYyFfwiujo4OaG9vh0ULF8DlBQUZ/Zb+sJbc9zAfywp3O/6QVgybOQOy7rwzo33EjYKAlWnNUAOrwpqjIcCq6+ZROX5gqf30NPrR9Hl25PjYhy9T87XjsK4ogEsGqZqTAdtPohf1LRzi9/pFfCa65dePP+E5uAiq3NwcWPPmn2HAgAEEqpycHAMsk5BQy48KhcxYyFrtbe3Q1t4GCxcsgCsuzwxckm0zZS2prcI8rLIHH4GDP3pIz7KMwFJzPfD88DlP/j4jjRQKrN70wJeVlYcDy3EAh3s19ajh9HbwhLeUEzCLkZmCe8LDBcYUVQDT0xFhaIw4MOD7fWetMD8r09IIhsCxY0bBmj+/RaDCPwRVJozV2dkJ+NfR0Qltba3Q2tIKixcthM9+9sq0rOBnrbAylF9X4eNU/tV6j81gFx5g6yHrzu9DZPbsjHrYDWNpHwu/Gxkr4x74TICF8zT4e9zlkC/FWFrW8YrwAJBzeDuMfu57iq2SQKVYjET8JX1nLQRXaemRwJohF3PxoPgNUb7qX3v9dWhqaoaBAwfCgIEDIccXCpmNpXhH1kK2wlBI4bCtHVpaWqCltQXuXXVPWmDhBkEXBScfuN948xeiU7nt2JZc+qOHjePO6xziuEOcuxTFfPadd0I0Q53Vn1BIUezIkTLX77gbER+JQE8CoL5LiVg53MtTfLZug6kYIMyGrX8chm5U3QxBGounJxp4V9/dbD6LvWlD4RNUWVUFb61dB3l5eQpYIhRmZeH4SfW78SaBhaFQaqyOdgRWK4Fr4cIFcFUGrMX7HeTJBSEzXVfDe6OwjKOWRpELZfIkIvh8dPlyyFmxIiPgn1hgOQ50JxwNrORRORwCA5137Np893HI3/Q7DSoV+rwAU4o/6/Jv94u15JHibkx/JyZu4+8gra6uhrffXQ+DBg0iYOXm5tIfh8IgYMmsEENhW1sbCfjW1lZoaW6BC+afD1dc0bvl/rhDA5mXb7ivQfschIqKhx6Fwz96yLP6qgQYAy6yfDnkSmCl8LUCgdUbjXX48JGUGguBVddpPSwEkQGUHAmtfzH7WEhd+eufgOEbf2d0FU1NxFM+ChFPQr7gNgqLJ/P2+po3iWUQWKyxEFjIVviHWSEzFgp3aTcgqEi8t7cTuPCvuakZmpqb4L7VtHzjSblVPvQIHPnRIx6m8jOXWucwATBrFuTdfXdajeWpFYpf0SuN5QFWgJeF0xXVdng7RU0pR4RA9f1Ka+kJUGGEBlbSzHxyIjUxY192wbch69K+663ensnfP/U0gUoCi8U7shYX4fFzsVSFbIX6Cu9RW3V1IWO1a3C1QnNTCzQ1NcFXvnIzTJ82rbe70+vtqx96FDAT9K8OxkDCln2psZxZM2HQXXen/Z6g7gZ8U6Z2AyGhtPRwuMbSPfBHWlShWXcqBw5U9e8tnohJT/0j5FXssJPU4izIYrJamvrRPFZhMveW/ndopj1yeoMnn36GQJWHodCXFabSWAguzgo9jNXcrID15RMPrNYNG2HfshvMmtE4059dO1ouSm41FzLWkLvTA8vfmszHs5fAOmINUjGYggdV4H1pk15InmuFbJLyNwbUdJC1Jj/1fyCvfIct5bDG0uGQQiMNZLSzI+Mco9mouS478czFwApirFTAYsZCcPmBheHwK1++CaadQMY6+vCPofLBR1S2ZwCVbC/4Q6IzexYMkYwVorFCgZWhxiKD9NChUlx9vkACyVPaAYCDEljCELXi3SKMF2nCeDj7gc8J4W4BRF4W9X/5NBcuEKAXY8L23+M5GsbPYrG1v4Y39zdA++iZgaGwr4yFwFq9Kj0rZMqq/u1qH/4xVD34qFoYMw2wuFYol6Ub8fQzaTXWKj09N313H3wsqhUisMBxkmuFouGvohWgM6Zm7iNS8xefhYjn2UyQsc554GrvPO2orfA/ORuyj7F0zcgs25t9+W3HZVQMnyAEVM9bv1YrjY68EA5NviJJvEuDlJ13ths4K2Tx3tbeDu0o3lvboLm5GYZV7Icb970NuTf/HeT+1d/1FT9J7+Mpi3h5ObniqlyU3GM3EPAQgGDaaEY9/UzafQrKCHujsai74cCBQ6Yfy89U7G+Vt7iAazCxaPdnhUF7isx13v3XeO2FJIbC6bX16l78Gvc6+9bOyb7iNhod09cRMgpQ/06Tq/HCmLtGLIKDkwuMj8V2A5d0/OLdX9LhUEh2Q0srNLc0w7kfboGLK/eqrtMEQO5X/w4G3PL3aU9m0AZdGzdT0lC54iZVphErrVL9L9C30kASfpYMifn33AM5s+ek3J8wYGXa9x4MLMFUlGo7DpQ1I7DsXKPMWtJwN3tqDXg4/wENLCxei+zPaiqxIAAtCuBbjMmzUIAKmzxCBpkMb0FAS5RuVathlG6l1uLEQXysd0yvsMrrGT5/7j+EGqT+IjQCC41RfxEaM0T0sNC6WLrjdZjScsw2COq1eaKfXghZ5y2ArHlq9uSs+QuTTi5NwQ0A7Y/+nEDT8d4mj5OuxLn9SwKWJzR6i9CK4QDGPCMYK0Bj+edukDv50uqvZ1RrJGCVlBwqiEQBdZbxbLiTlBmqrhOgri1hXg+3G2zxGU/sBQ8sMRP/S/9KLgigxLuezx1bVDwLBGhxr5BsZ/1mm0MsNo6ASxzaatepEAti6iUy7OJNNBeAqkLtHL0QDkwpCK0VpirpGMbCkk5rC4yoPAQ3Fr9tFgunqSf9SwDLubYSANnzF0IPMpNZWFMtX+xZvZ58KM765OLjtshsQiSHvgDGwq8e++yzKTVWmHDv7Vo7Flgsyv1eFl5BMYBDjQkiGvIo/Maopi6zlo2G+aL7P2+7GfC9rLFkSGRgadFugMZA4tCoFx0n3uEsVJQo+coiJiLRqZ4xg1LkqmACWHhCnz3/ewQsDIUYBmUolMBCnZXU3YAGaWsbOe/Ld66Byc11ZhHNjFe9FytjmGV6NcOwSA9mKhyorUQ81waDQqQp8YAL4595NmUYTAesTGI69bzjhvsPHESi0Eviehv+8PWOHoADDXFVKxQruXkb/LxfiRprzpN3wLDyXZ4lSyxDqfDoYSjfSqoknHkVe0J0MmuF/lDTyqpBxkDzLYmCzFU4ej7sO/NiU86RbTP8+X7xjiGRGEu3zYyqPgxf3rder4Khp0AKWplVP8cLcPoXh7LA0Ayli8jJwNKaK/R1HP6lRLsMoROffa5P+qo3gylwYhAFrP0H1wI3+zFj+RhsR3WPT7zr0k5IryoSxDkaWEpfyXVxNEBZQyUBSvhbJKT0sZBMpahTtBZq5Mlxc9T6qd+r/41i2HHFKmE6JD4295swcMBAyM6xjX5htULubujsUD4W/t1YtA6mttarkdO8kqtcQDMNoGgFj4RaOk6BK1mEyxBpxbzqtwpkNB+worNnw+h7RLnJp7HC2AqPIAGrYF5GGssAq6Rkv7Uc/CFRPy6pj0NbtzpLGWksAPj0779PjIXAKu9xYdJATPW8hqh5LEOiCYNCWyWBKg0pS0BxaCRw2cXGCZYaWJvz58L2CReYUMg+lmQsCoXdPdDd0w1dnV3Q2dUJHe0dsOjILrii5oCaTyt00XLvMnZWe9kVMNSsSRYoHOKYcbhhj0W7tBGSwaUGrGKIPBaNwKBYDAbfcAMMXfmlUI2lgLXN2xWvfSxmrLQ973oFVjpd+0pKVkf0gAoDHCHmEUglx+JqbcJeaKxhh3fBvKfvpBBbjv03EYBJAyK2y8HHWHQBJa3uFc5YtL1oiSagmCq4thUkqPDfFArtIuS0PWkuF97LnwNbx56nuhuycEoB7EZU0DKhsEfVC7EAzeL9X/b92SwE5QltuHqYCIee5YDNSq7qu0lbkdZX2RwzEi0lB2wtqLYYlGTh2kuIe51FHotYYOWv/FLoFemfvkhu2BurYcWy61bTYSsuLimIRJ21ONI5DFhVLQnA1VRZ6iitJWs53v1FjTX88G6Y/9SdFAYrehKwpTUOy8dmG1sBgba5KQ6LR2TRCSzvTMCkPPQU9OfqEGgAx0Dy+Bx6IUx2iNlW0PcU+thA5kXHBXPxopnsb/3wjOs8bTP8EzFUcXeDrBXeVrEdPtXRrOwFDoG0cqsOiSYrFK/zYgW8qhcDxYRBBY4Kx4VRemU0qb0U0FTrsWS4fVlRmNLdo/0uBcAD2VkwOBYjxhqzajUMmBPuYYX5V3hm+wEsazlYI1QpZ3zc0uXC3toeL2PppVhkazLDi5njc/cvVU67A/Czqm5YNCwLFg2LEoNtaY7DxAERWDwcJ8wC2NwYg4kDIzApTzGFBJRBNGFOa6t0RhpuxwtjauYyDMVZova1GGBv5E6GdUOmU9tMqn6s7u4umN7VArfXFAUAKs3SwD5RL0MdhzS8Z2B5QCW0F26zJxqB6T0xAuLe7CjEcc0icGFydxccyM6GQ9nZcGFLC71+5vMvhGqktPrqsvMyGpe4fOm15gzROSveuy9gGTnR2+44sKmsS59f25MlTrNnlA4DbOGTd8HIcrVo+EsNMajodmHiAIfuCWT52mJHxupOwJamOCwfn+MBVgUymdZnm+tjsGhktpiFIDVjeVpataZS2sobElU4VO0xt+ctUJP4ilE6tLBUXDE2326vKYbpHU3BTKUX4LRMptfekYua46pnmpFM6DOOuguVDsBIzOpcF7ZHAGbFkKVsllcUjVC55ixkKXwfuPBhVpQAheDCXZjU1QUTu7ro9anPvxA6LjAVW8mMMJ3GSpoqsnjvh54uB2mYco1wT00PNHVKo9Q/y4R3NSncicVP3g2jNLAqYi68VI+1IYBFQ6MELOlbocj/6eEuYjBksoruBGxuiMOi4VFYROHSgRcru2DFhFz1xYKxyjs0+ETvPX24WY5M2A6sq/S04QwqNlL/lD0R/pQ7IVSL4AtLmipgSWN5UghU4VAvV5cmNOKu4QkvAxfGCgOUWaswAjAbGwxdgErHhbVZUZgRi8PZsRgxVXE0Cks6Ok1WqMR+AkpysuFgdhb9dGQr/LwhN6yE4V8K1lep2KovYdDIJfzHruLigiwnshb/LSdgM5oLAI40xeFIY8x2kBqOStZa3OUw8vAeuOjpexQDRRx4CcNdrkPA4pU0yY7QRuhLtT1Q3oUFPXVeF+VnEbB4PzY1xgAZDFmNxfuWBlpDGBYNVwdT+qZq8XH9jACU0VZkP9jskEH2pwET4LWBEwPB9anOZvhOtTcEJgNKiXKP/SAAp9ZoVGJ8C+USLnwahboW54URlz5yVkwBC5/fFY0QoPDYIhtNj8UsW5laotVW+JkTkK3AhWE3rIQRX7ox8PekEu29nbMBhbsHWPigqHhv8ARs6qxCc5cLO6q69DlX4TCMGi1RuLD8gZUeZjK1woAsEMMhggu/ZPGwLFiYr9qD8WDifVlnAl6u6YFF+VFiNdRleFsxLsd70Izzble3N1mjBFjSGtLMbC58d/TCwOmkbq8uhk+1qxBIIZUtBvlYi3fzuqe0o7I8pd1VqPt1FGCs68LohAtVDgAu7nZTT9xrP7gu7EamyooQsJCtkgxVkTXW62wQgXXWcy8EaiRcZBz/wm4eYzSkf4vfG7iAAL64u6h47UdNWuHD7QFg3cEOohcp2D0M4dtDZIxLn1oNY8qKTCsMGZ6awYyzzv4WZiD1PTAxJwKL86MKuMbDUt/0Um2MMkj8jEm5EZVp8k3YDfiUMkT1BeDJCi2AmL1ooK32tfDMvTZoErw2BEOiZeTpHc1weyWylV7aV4S7QKDJbFGDjUClNRECA5kF7/8UBQIVfvSceILCINcIpajfg8ACgGmkrVR2SFmisCs8gHNdmP7Ci3SE/ERAwHp7uzhr3i3uu2UJzTQjD6+MT7y1fxlfTwzbtau4wInY7DDIfiis6IJGPKnycPu/yTPU3oW565+HORteMMCi0TrCEDWlGi4ZMZMZo1T/LK2pyrtdeOloD3liy0cLUElQG4NU/3RNodzVYO816oyfpXaemMYF+O7ERZ5L5faKIpje3uwBluNhLgk4UYTWAKRFFAgISmwzyFh8/0/UIbZCYM3yAcuAC1yocQDy41rMs02hfSsJQvzcYStXwsiAMJhOW+EP763NwAfLB6xdBeBETKeDpz9L2w4NHXHYWq6zQ5+0YuYyl4YeWjHmSBFc+dR9ojYogIUba6B57AWtuYxIN6yldn1zSxwWD1WMJn+MNEjlfijbIVnMS4NUMhd3P/xp6ET4n/xJ9FHEVmV7dAjUVw+iBHdC35Om4se+UMmroJkQaEKhEvGYyeH99ogDs2NxZYwmiXpV6mEfSxqqsiZIYTAeI8ZD0T4qAFiptBX+3t7UB1Ou/oUftmtXka9uKFexV2cXgVXfYVPvAMKy1KnP9FcfuNkw1pauBCzUXhWHRMtaotjMWR93U2hNh2YrhkoTggWiPU48zyEhyzvsa/FzinyJobgB0JMlJlz47llq+snby4tgeivbC5rZGFiakUxJx9gN1saQIdAwlgCOWuBViW9TK9RtMBJItvQTUALSYfZQTrYS7gkXztZhUM6PlRFbZdh/hcdG6itPNGMkFO7YtTriyInYvMBCFjtwrAdK6rpT5ISi9quBdfVT/wzjy4soBL7cFoeJ2RFYlBfR3QsOoBVREbeAw8cIHjrbyuZPThbSJA9GrBNyREgMyA5lDdHLXC68NuIM2D9wCNxeWqSmW2SxjsD1AEuKeb1dXGV8yCaINQSO8kdtmYaZKgl4IsTJ7fdlK4cdnyvJzoKhsTgMicVMh2lpTjZ917jOTshfuRJG33iTvdD1dZvKt5Jslc63outT1welZkjyCQoLd/ka//zzZgHUdyRg0+EOK2kD1LsJUXouh3FHiuELT/+QWKsi7sLL7TFYNDAKE7Md2NKZgPKYC7ej8al11ZaOOCwalGWyQdppB6CiBwEXEoM9sVgzCr7NI945XfT7WipUepiLhLwLr408Aw7kDYXvHNyTDCxkOq4JSt/KaCoNLKmptLZioKnQZvUWa69qB2B4XBmiYcDC598clAeTu7phUncXHMzOhiM5OTC+qxPGd3bBcB+w8DBmwla9CYN+tgpkLHyycPsuYZZyY5+ag5Te5Diw8XAHHGsXtUN95uUoHQVmHWpcF779o6+qxj9krY44AYzRuWxIFkzK5v4rB15u6SFWMyETABBseFs4yM5bJa8Sz79l+PPuiEdrWY2l3y1LPNqJ3583jMT69JZmXbC24p6zQ+Nj8fuRqQSAPGI9EFgcAq2oR4Fe4zjkVzGw9mZF6aumdHcbYxSLzIUDBxh/C793QVMTZYmzXnjJc1gyAVVfvauUjEXAKiwsACfqE/EWYAgsBNV7pe2+82opw5OU6bR/6dP3w8SyYsVaCZfAhbdlg7OIuYytgEVrdOlbY7BoQIQAtqUTw6cDCwfajgNjq2gC84Q+3rMggFEo1O0ziO2g4rS2HSh7TACUDBoK05ubDLAIUGxPMFNRaFSfTRJL2AoIDBkCg4AmtZXytwDeyY5CbSRC4MLPw5LNlJ6YAJbarj7iwI68gbTNhK5uGNfZQSJ/tgSW44Bc8znsojRslca3whPmJtx72RRNCyzcYFvh9rUAcliYF1j4nesPdUBdmzIo/Td/KMSTsHD9y7DwvVeMiP9FWxyW5UVhUpav70qHw1806c92ACZmOYCsponR3CVlhQJQXo1lqFPF1ABgKQc+tf3A2WI4sCyADGP5Qh0/bw3SZPtB+lwbcrKhDkeN64aJK1rbPD4Ys1lDNAK78vLgAmQr1yWLYcyNNxnJorJANDOElOCuEHMCXXhp1dfFI8/WST5YUBjENydpLP7ErVsLVzuRCLUbSttBPq5rj8M7B9rMTvgBThGI/SMAmHR4L6x45gGjoypdgAlZmqmkZ6WzwZfbVbgkUA3O8maBeu/NcRHa3CP5UjEWfobOCvk+DFgeINEZFg2D2lYgXa8ddSvYrRlKLVhCa7FoV8+zjeDVWmx0bszNBgx5U7t74MzublN0lp6V7JLA943+0o0wVgv3TEIgHo7eaCtekCmIWEKB9f77hdosTWYq1euuRP3bB9qg1rCWCIVCI0uA/cOPvqYGY7BBii96hnnp4rIDUJlwoTzuwqJcbszSP8HstV+t+3yHgHBoaokmBPoYSmeMxrEXTry0IaRDj6CkRSc1M/mZSmaFEkAWWP4SjwUgAwsBtGVADpznKzr7DVa5/bkvqUWfMgVVb7QVfm4YW6VkLHzx/fe3EmvxoAkl3uVSJw6Bau1+Zi3vidapqBLwOju86akHYXL5PsNa0r9Sgyf0+EVmMLmX/svA3/AnuxkCQEVPeTwtzaiZ2A+hAPMCSjIWA4qqOj6mUoAIYzALNOtreZ16GSqlI89Aw4a+6T/4IdUBU9UCJdsksVUKjZWKrdICCzfY8v5WT2HahkL1dvzut/a3QU1LjDpKTVYoJY124PGknnFkL3zlmYeVdQAuTOTyDvlUAlhBgPK5774+BtGkLADkBxM/ZkblIrQs6VCI9In7AGCpnicl1Nmn4uekWA/UWvq9CiBcjPZpLWEzBJWA/IYqKtLGSATysFv0SzfCO+Nn9RpUmfhWeBpSsVVGwNq8+X3DWmY8oWeBJgeOtsXhzX0415Ea/SJ5S3Y54BdOPrwPvvq0Ahb2GJV/5BMtytKDLDgtlHorkLHUN3DXAwPMjmsUKkv2YwUwlkfE60ZA7ssi9zYJYGIdRsKfKsUoo10xjUoSLcOYx8Io9Wsty2DBWktuj+UabDeWgy3w9bLcHBiDoRJcKFtxKzy+P/NVZzOtCergE5gJSvYL1Vhyo02bP3BJFpnSijVNmcF2VnXCjspOSxViSm6psfA8r/rRbUZj/TIeh+uzojCRwKS015ZEAhZG1UzN1P2An6p77Ll9xu4fd5AyYXmKOhbo/pHRkrlS2Q++LBFPoNLuClCqeUEzlwBUoOYSoY9DJgHRV5C2hqhP1GvgIrAwA6SSjbY0GqNR2DsoD85taCRg/ct5yYt+ynOaMgSGbaifT8dWGTEWbrQRWQuAtJYV7slAe31vC1S1qL54vhnC4NDjuvC1px+BqWUfEmJeoVEMDizQIfF9F8MjwAKaWFa3eZgQqJkoqMnefzCs3+Fp9POId670CGB5yjnCflCRUC/saYCVLNq9gFLAsGymH/tEPmstI+aTQmByqNw5cCAMjseoSI3F5r15eTC2sxNGdXTAocEj4anpl6SBh3q5N/1WqXwr/5dlxFgEro3v6+K0wmMQg1W3xOBPxc3BwCI3UQFl6uEP4ZvPPKp0luPCH1hROwATwIFlUR0ak8KgBJaXmQIGglm/SoTA4KxQdD2wltL7Susu+oDEHZweptLhUIVCZiFZJxQGqdFXSlNZX4uthrDnVfcDA7AoLw+QqXj/zmpthQE93fDuuFmwYbxe3iTAp5Iu04urvubxnNJprEzYKmPGwg3f3bixIAroxnuZikMhM1lhRQdsK2+37SwiJCpicOGsIx/Ct57+sXHaX3Fw4IALC5wILBCLa5pfnJKxQg4FF50ZzQJchpU0Yynn3doOfKKUIak1FYJBA8wPtDCNlWQ7aJFuxb60GQTAdHhjcU41RQ1GCSwEPYKrOSsKYzo7YXRHBwHvmU9dAkcGj07LWL3xrJScgbTair80Y8bCN7y3cdNa11Udpn7bQQLuv4taoLKpm7bhLNGGRBWj/uWhvwVsfMFPwtEo2Dm5gJFkxLuXoZRYF7mgGH7GF6ZhJCO5hHMq7QgOldw2w8ykQx5LK8NY+pf4xTqHPu+91V5SzKezHySAvFmgDaF+YOHjfYMHQV5PD4VB/FkPzlv+sYKqV4zFe7p+wyYS8qmAVdUSgz/sblLAElmZyugVM3zz2R/D9PIS+lgGmBnPqL/M2A/4OSziZatywOEz/CUMWoInZavJ+4MnG/FmNLoBmA2BfgZjzcQMZh9bER8EKHbek5lMuO2yphhqN6C9kVy0pt+SAbB6Uws06xdef12vSKhXG1NIfHdjAThAo3l4WFiQ5qpo6oFXEFziBCtMqdDyzed+DNPK9yt/1BjxanckwKR1xVmpwZNwFTxUJgBHwNY2CEdDBrhXs3uBxCvFUig0tpZiIqWxbGg0AEthP0gtlWRHaLPUr7WS+rdS+Fpcmdog9VXAhecPf+k0FZ2+XoTAPoVCftO7725cC45bwIAKAhZu+35ZB2wqVa48Rx5mMMwKv/XCT7XxznObsiHPA2UBXp3/Ocrqlm57w+LJREjtm5mQqBlJGGnme1Vnl2JQMUCagK4ZTWkqC/4grYWpfJjG4qxRAk2KeVPyCfCzrP2gskjZgzV05UrYVVoFY7e8E9i3hd/Bt1TA6m3Jpre6SuK414yFb1679t2CSBR74zkkht9vOtwOmw632XGj+iBMLSuBb73EwNKAQuEuOpP/eME18G7YT/oAAA2ASURBVP/mfU4xRMKFpYVr4PrCN1LOGcE/zh5qWwtghlJA9wJKsZjK4iSj2axQM5VgJdzO62vx42R/y8NYwkwNdOhdgKzZs6Du4ivhqfJW2F1aTT/rypp9cGnNXgU84X3JE5pKuPfGBOXPzDQL9JNjn4BF4Hr7XZqhRoUuBhaHMgk0AATXe4faDDPoKwHu//l3dCj0AgpD3p/mXw3/ff7V6kRrE5G6BxIuLNuxBmZWH4TZNQeTyJ6p/cjoUVAxdgx956SaWnDJT3LhjLpjtnYZwFwGWGw3CIbyMxUBi0K7DIvWhUcA1I4bA43jx5v69ZCKChhSVWWMVX+I7Jw6Df44ejq84XVtzO8sqNkLl1TvNeMSjYbVWwQJd2SqGy+bB3Omjs9ofitzcTpw74qlagBqb299BpZmrtUfRRdTpLbOvBdYyEcbS9tgPYKL22hcF+7/5e20v1a8q93/+bV/Dx+On64BpYS3AphmFHycAFixcw1dvSt3/5lO3Oa5s2D7/Hk0Mx+vhaPCnguJuJrmceSRMvj0th0w4WgtfZefodh1YG3FoJHelWQ2P2Ph5+379Dn0/VUXfUbtR5ZekweZRiz/m79hA4z+4AP6DUdGjIVnh0yGkrzhafulJrceg5tK3qH992ukB+eh425P65wzx8EPbl1icJGJplLJTubWQhDo+gUsDS4yThVzWfEtHzOrrT/UDu8eaFEH5KPZVL71h5/BWRX7PeIdQVUyfpoq4QkgkZjWjymD02BDBpuUKIeZeU00+zHPJZqVrRZa4u/iqbRpXis9E9+s97fCgj3FXrNdZoU6ZHEIZb+KQKZ/Az2nAVp0zlyoWLzIzBufOyAXsrPUXFt8bOKxOPTEeqC7S0812d4Oa4srYcuREIoKoYrJrbVwUfVeOKNFXSB4KxsyGp4WjntvfSr+nP6CStHKcbi9tfadta7ran8rCGD2q9492ArvHGilk0nAqiyhg35w/HT412u/Q4CxgFIAUiDSGgfnQxCAO8OtgLlD2+xiSwPVJLWGsRgAemJaXsCS5g5ta4Np722C8xFcRltx1sddyFaL+Q1SJfbVvu09dy7UXHyR2o/Bdpm6oFXEeBECnMYbF3nCFVrf3FUOW46gRdO7200l7wKCDG9oiqLGwltfQYXv7auuknt+XIC1Zs3aAifiUI98MHN5MfzOwTZYt78ZrvzgNfjs1tfg4IRPwa8+/x2bnWlGohOHQNInj04+PUbAJeCMRAXMHdYOQ4YOgcGDB8PgQYMg17f8LnlhYj1nBFZXZye0trWpSf+bm2Hqe5tgnmauMPEu9ZXZH71fxefMgdpLLrb7MXiwZU69RB0fGwQV/tF+dHURuHE/cI74PYdr4JXdloEyhdhF1cVwUVUxlXEwK+yLT6VPHDgJ9/Jly65bl+l3h213XICFH47gch3AuR9IzSt/Sn+8b/Y/fH7d/haIPKNm8F1z/jVmfjRmLOMjaWCp0KjYC7nk7K7dcGZ+FIYNGwZDhw2FIUOGeEJhdjZOnKYnFNHAwhMqV+3Ck4lr3zQ2NkLetj0wqbRSMxdqOOQi1GAJzZDyMfdhuVA7/UyARedDfn6+Zz94xVbJWMS8iYQBFi37qxfRpLUOm5rgzd3lsK3StntneoIRWHi7+p/+IaO5FkzYE2HreIRA/tzjBiz8wNdf//NqiDirDKgMrngaby+jHarvhrdKWuBgXaexI1ikm9CkxZZy7BWwBsUb4fzsUhgxYgQMyx9G4JLrDspVUpmxJFOoEKQWr0RQNTU2QX19PbxVmQV13VFwEwlIJOLqLx4Hl/8tHqNmGzMQYNk5o2k/EFi4L7wfvGIrzmeK4JKMxXPF8wqtuB8IKt6Pt/fVwI4abEHK/IaZ3/+ZPwmGzj0n8zeJLY8nqLzxqU+7k/ym115fs9oBZxWzljVRJYN5Zy9FcK3Z16wFu9U0pHY8wFKsdXb3bpgyPBuGjxiumGLoUBUKBw8mfcVrO/NUjzIU8uJKOOE//mEobGxoJGB9WN0MG+sHCSAlIBGPaaDFiG3wMd0nYnDVlIEw58yxCljD8w3AcT94xVZe8IkBzosQ8OS4FAp5PxoboaG+AY4dOwb/ue1YxmekN+sIBn3o8QbVCQEWfuhrr60JsSEEQepwyT/0zQ8RXE0eOwJfQy2lRRVpLWSrc2A/jBo1ioA1fPhwCoMcCpkpePldPKFmoXDUNp2dtDqqPKENDQ10Quvq6uClIwMMcNIx1zfmj/LsBwJc7geCi/cDQY4A9zOnWU+6pQXkfvxhTx1UtwYPreNjNnfKeLjvlmssVjIYB+if8CtsXGDGqA7Z8LiGQvkdf/zj6xQWleTSIVBvYLWX93lkuTV7m2DNXmypVdmfGoShwyC4MDjeBPOyD8PIkSMNUzBj8aLhvPyuXGRJ2g086T9qrJaWZmiob4T6hno4VncMCmtisLcpakNhQofCOIZGxVQIuLGDsuCLs0cQsJCxEOQSWGh90H7k5ECWXluaNRYv9OTdjxbDnMhYGw7UwY6aLuW5eBobXUBAkeE5ZVySj5WpT6Uu2v55VanAd8KAhV/66h9fX/1RUkaay4ZG255gvtwHPAyLB2s74EBdhxHrbKx+qrsIxuclDFNwKGSmMCcU52rXJ1QBIkErd+GfPKEYCiVTbKvugqKGCAHLaisMgfYx/pxPjx0Ai6fkhzIWLgeci8DS+7Gl6CAsmjONDFK5elhyKKyHurpjUFLdAG+IMZt8EvtjI0ggnEhQnbBQKH/AH159zQOuIAbjK1I2K+B2GBrfKFJaQ2WECZgR2wvj89wkxpIh6MXNh2D34TrYcbBGAcR14dypo8l9v/HiGTBt7GBavFIxVguFQQQXhsIjDZ3wdiXaHAgkIeL1Y/5tnztrEEwZNRhGjhoJI4YnM9aTb35AxujWvYcBQcW3hbPPov355nWXwOzJYwjkvB+s9ZCxUHf9bqfytVCYzyGWOq+/EUofyxPHVLyDJ5Sx+Ev+8OofV380Q4It/WgGS9oJXy87A21NcT28jgD7qDtyZuJDGJMbC9RYa4rq4KUtpQqEaBeQVZAQ/8Z0Pw6zJ42Aa8+fDJOGZZN4l4xV0dwNaytwUlqdFQqAybN69bRBMCl/YBJjoXB/cf1uePx/NqUFwdeWXAgrLz2XQEQhuUGJdwR4aV0LVMSHEpgw5NGtDxrKr6mOl0+V7sedFGDhTrz88qtkopoDJH0uvZcqV/RrCvsT3iiqg7Ldm2F4tEOd0OHDKRtDbYPlotd2VWkQKXZDMxV9KJxYlHwpvMeQRo/jsOTcifCZqUPJcuATerTdhbfKMPOzoc9f6FWhMJfCIWo9SiLyh0NlSzfc/5yq4WV6Qzb6p5WXmOyUmTNn4CC4+qrP9ktDEdPbbpF12Fd1PMzPTH7bSQMW78yLL7+6OqJFvWGsEKYike8Tr0V79kBxcRGl9uRjDRsG2+scWFvSqGZ5weo0lYC8bEXAoj8Glvr3PdfOMP4RhiQEFWZjSl+pzwi6IagQXMhQ7Kf9Zm0x7KvI3Cbgz126aAYUzBwPjU0K4Aj0UaNGw8WXZDbSJt2J9k88m2774/H6SQcW7jSCC0V9uh/A3o+8Ly4qgr17i0kU4wnNHTYKauJD4U87KnToY7ZCUGBIjCuQaWApzaUZLJGAi6YOg3NGRcjHQmH9ZmkXVLf1kB6z7YnBe/rX5w6jOfFxPwqrsJiMM7lkfmPtNPfMcTDY6YSqykraD0wwEFQIrv7eTrRID9u/jwVYBlzIXKL7MVMN8crLajIxZItFixfDkCFD6TGD67+3HTZsYwBlwJUMtKvPGgDDIt1wtD0BbxxsNwBNd1KvnjYYxg6KQkNPFF4trk+3Ob3OvVH4b9kfVVlZAcjGqLdGjR4NF198Sb81lduPfqqMfkyKjT42YMnQKNkrEx9mX3ExsRbeLi24HEYMxx4mdeP376tshH2V9cRar2wuURkegYuzPa25EnGYOyIC54zOIlBVt6rRRfYDk30kfl3prFyobo3DGwe5vmd/AYIIr5ubcAFJBFIa30ldMC7MnDkbZs5S4wIzOR7yJOL2EYCTqqeC8PWxA8uwVwahUf6AvRpc1y9LP9SJ31dcXgfFZdhNqgzX3YdrYE9pFcwdlQVj8yLw+oHWXl2oCJzxucodr+rKIksAwxqDqFcfBgAIrP5qK/+02L3dh+O1/SkBrDD2Svcj17/77nETuPxde3R/edB3m7Tf92JdXe1x0UP9+T0fh0BPdX5OKWAlsVca36buWB2MGjnK/r7j4PP0RfOZHfgYvt9x3Y897J2yoTBoxzhz7IvG8GuOT+rjjyvjSxdJ8PVTjrH8O52pNZHJj/2kbHMqA4qP8SkPrL7qr08KiOTvOB0AddoBKxBgH4OmOdkaDDVUwoW30UI4WeWY43FRnjaMFRQi6Tluy9EbfFI0GWZ5J7O2dzzAJD/jtAWW/BGfFB2GYDod2em0ygr7cgVhB0UCoCDiwGUuqEG0p/qNmQn383QKdemO6yeCscJ+5It/eHU1DlM2JaNTRJOd7mEuHahOC7shkx+R6TYYMk3WoktIJ1KTIYB02z6J708aK6U67p9oxsoEcBw+5bYYSvFxunBKzKNvqI3wn39pAAo7xv8fGTAQGvu7v9YAAAAASUVORK5CYII="; + //游戏手柄 + public static final String game_handle="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"; + //矩阵表格 + public static final String matrix_tabler="iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAYAAAA8AXHiAAAAAXNSR0IArs4c6QAAB5FJREFUeF7tnet1GzsMhJdqJakjtvtI0ortVuL0Ecl12K1oc0h5dWRZDwKLAZfQ+Ne9JytiOfg4fEtp4B8VACiQAGWySCowECxCAFGAYEFkZaEEiwxAFCBYEFlZKMEiAxAFCBZEVhZKsMgARAGCBZGVhRIsMgBRgGBBZGWhBIsMQBQgWBBZWSjBIgMQBQgWRFYWSrDIAEQBggWRlYUuEqzv9z/vz6Xmbf13fYtp602TpmAVsbar+zGNdwWWcTgL1CeY0rBOY9q8vf55igzZ9x+/n4o2Ql2KJqvtumUjbAJWBmoc02O1YOfoScP6ffPyEBGub3e//s3VJw3pOWvTogG6gmUG1CFJAeGygOq4sWXIPAFzA6vY+jA+ItwlrcaHlrZvWSeoTo5wuYCFFKskNZBrobXyci44WGihooH17cev0dIBT5XlARcULBeoPpR7f32B1gWd7Kl8xPiqBVywZHhC5dECo4G1G0HgBvQQsDyhQgvkBdQUp8yct+mfV1zUxAcClsc4YS98oIG7d3eIHJ+ag+XqVgGhagEXwrX6BItbOrY9JaCBmoI1e3yQgUlj2YY49xdlIVRKxqVN6LzfmsubswBt7Vq2YGlX1wEtRpq4KM9rlyusZ4jtwSJU5kyr4DLOgylYmgpFWdg0p2NmgeKZ+aLBEm5HWNvvzFyE+njrRm7rWARrMXBqJlKWvYcZWJqKWM9EFpPVBbxI63wQrAVAgHgFgnWjlyMQMB2WSbAIFoQxgkWwCNYlBVq3EEh2Oi60dT44eO8YniU39K7BKouAu93X/UXXcpfO8LJmrzHoWMox1rWVZYs1sp5jECwFWNcSPnURc+DqPQbBEoIlOqGq3FiNEINgCcGqdZLJtTT7Xx4xRPAOwyCtB8GSgiXd6FZcv5ceOdF0uegYBItgVS14SOElWFKwhF/vI+1CcpY9ukJ0DIIlBEsyNtEeJHSJIbmYqpiEECwhWBJHkXYfh31SraMsNQbBUoBVA9echE+AXYNryTEIlhKsnPwv39GZhvLFt/luotX9w15jEKwZYB0fbLOC6dw0LSerlxgEywisqjn7DT1EsAgWBHeCRbAI1pIPlkGy03GhdCw6FgRfgkWwCBa7QggDkELpWHQsgkXHgjAAKZSORcciWHQsCAOQQulYBo7V0x4ehKIThRKsGWD1epn0mANEPQiWEqyez0pJDhRqz3wRLAVY16CaEqdNSs1BwqXHIFhCsCTn0bU/kBkhBsESglXrVpOj8JZO/XRhjsMfR+nu22bQFz1LNxjgUiwdS+pYAZLuAS/BkoLFC6tVfRvBEoIlGVgv+sKq4AetNPUgWEKwIiwFTJZTOxHRDKoJlgKsGrg0yTi5In7wNZRfZj6Kb7LxikGwlGDlBPV6mfQYLkQ9CNYMsA4TFGUj2qoeBMsIrKqp0g09RLAIFgR3gkWwCBZPkEIYgBRKx6JjESw6FoQBSKF0LDoWwaJjQRiAFErHomMRLDoWhAFIoXQsOhbBWqpjWe2vXasf+ottLQmjYykdqwg3pseSDP7C6hcmCZYCrBrReB7r5/24TbufNq78s9BsCtXdLZ0aqPaVm3EQD3m6c3o/ZAyJThZ6HbPbH1iCs+K8sErHqjRr+Z0/Xlitlna46a4wwmXSnGp0PdgVCgbvXmKhk06w6l10cEs6L6xWZcUrH+deprvBe+1MKldYc9Ezfy7CpViCJegKS9IFP3k7ZzBaC/BSY0h04nLDhwI1os1JeO0605Jj1Gj0Ze1pxrpf9+tYUwWycMN2dT8O425bZ9f38RdWBY2PYFUMV6NsRFvVg44lHGNVMMZHhGNRjrGITLUCdCw6VjUskgcJFsGS8FL9LMEiWNWwSB4kWARLwkv1s2HAyjX22LytVvbGH5RsS01SaY4YnZPZbK9QA5b2IN6NM1NV/VhgCU8eZIUsW0mV4jfykLT3sG7kto6lAMu6QjfCzcVq1m6gHxaiPQni0hVq7Le8WBrW75uXB0IxXwENVLsUpOe31z9P899gV4KpY2lmIsetpvz/als2k0/99XRp1CpJuZyy6X7hr9yxvPDV4dfexeKkxudcXoso/HdtixGFScM6jWlj2cJE8Z0e/vI13aC41m5l7lhTy5JelFTrFbgLdWmgH8J3AVZ+V09RIo7PXPUDzcxNx1iT88wda0kdzHp8II1v+bx6AqR8CYRbQbrCPVySG8tKUfYfC9QleoKFggoKVhlvecEVCCzxwqayUSKhgoPlCVeUFXyP8RUaKhewPODyEEppDOKPocHy0goyeD+lJrJb9BJLTIniA8iJj6dObmDBnCvQ+Gri0Ny18oJyGp89dy1cwTqcMeb//nQnUNG6I65hmcLVAKjp/ZuAdbjelS+dFsjSeFe918UtndPNcLqwO6ZN3m/1dKjjF2oK1jmTurTh2lIsjalafaY3TRYJllUyWE47BQhWO+1DRyZYodPbrnIEq532oSMTrNDpbVc5gtVO+9CRCVbo9LarHMFqp33oyAQrdHrbVY5gtdM+dGSCFTq97SpHsNppHzoywQqd3naVI1jttA8dmWCFTm+7yhGsdtqHjkywQqe3XeUIVjvtQ0f+D4gp4B6mLQzGAAAAAElFTkSuQmCC"; + //矩阵数据 + public static final String matrix_data="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"; + //三维坐标系 + public static final String v3d="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"; + //数量 + public static final String number="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"; + + //购买地址二维码 + public static final String purchaseUrl="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"; + } + + + //音频 + public static class Audio { + //开启 + public static final String switch_on = "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VgAgdoUDwE6EDasjnBSNBRYashIACAcAAIxBiDHoJJRSSoUQY9BJSKW1GCuEGINQSkqttZg85xyEUlpqLcbkOecgpNRajDEm10JIKaWWYouxuBZCKim11mKsyRiVUmotthhr7cWolEpLMcYYazDG5tRajDHWWosxOrcSS4wxxlqEEcbFFmOstdcijBGyxdJarbUGY4yxubXYas25GCOMri21VmvNBQCYPDgAQCXYOMNK0lnhaHChISsBgNwAAAIhpRhjzDnnnHMOQgipUow55xyEEEIIoZRSUqUYc845CCGEUEIppaSMMeYchBBCCKWUUkppKWXMOQghhFBKKaWU0lLrnHMQQgillFJKKSWl1DnnIIRQSimllFJKSi2EEEIooZRSSimllJRSSiGEUEoppZRSSimppZRCCKWUUkoppZRSUkophRBCKaWUUkoppaSUWiullFJKKaWUUkpJLbWUUiillFJKKaWUklpKKaVSSimllFJKKSWl1FJKpZRSSimllFJKS6mllEoppZRSSimllJRSSimlVEoppZRSSikppdRaSimllEoppZRSWmsppZZSKqWUUkoppbTUWmsttZRKKaWUUkpprbWUUkoplVJKKaWUUgAA0IEDAECAEZUWYqcZVx6BIwoZJqBCQ1YCAGQAAAyjlFJJLUWCIqUYpJZCJRVzUFKKKHMOUqypQs4g5iSVijGElINUMgeVUsxBCiFlTCkGrZUYOsaYo5hqKqFjDAAAAEEAAIGQCQQKoMBABgAcICRIAQCFBYYOESJAjAID4+LSBgAgCJEZIhGxGCQmVANFxXQAsLjAkA8AGRobaRcX0GWAC7q460AIQQhCEIsDKCABByfc8MQbnnCDE3SKSh0IAAAAAEADADwAACQbQERENHMcHR4fICEiIyQlJicoAgAAAABgBgAfAABJChAREc0cR4fHB0iIyAhJickJSgAAIIAAAAAAAAggAAEBAQAAAACAAAAAAAEBT2dnUwAEQIkAAAAAAAAuvakYAgAAAOSFo8FBAQEBOz+vdnNwkDw8Ozo7PTo+Oj6/joGDhYGOiYmGh/84/1b/Vv9W/1b/Vv9W/1b/Vv9W/1b/Vv9W/1b/Vv9W/1YAAABEjk0x+nhoIse+G873yB63n4prKDRYnMyNVtNcXS0FwRIEwg7X1TYoCoIgCKQo3q/PjDKwop//fP77ALS+mfVHnLaC0K1vMSRGZOwvCPMBHEQPV2TuAPRIRC0lSlS1lYs1GHnlwsaKNbP7B+ECadXzslUPQVAbiwgAANqp7vJTQIADVztdcf9bprgCiVx7v4qd6i4/BQQIfrXTFfffOscWR569b+MbkUW1Uq1Ua6qVaqXdxoZjFEBGWW8kAIGEYwIAAMMwDAIAaAAAAAAAiFoUVNRaY8UeMxISJLU2OjokJiU5W5M11lhj1AxWTIoATUBVVVW1QIYgKAMIKSR6aSJUAIDabDIAIN3s2Cx2txbfqQA4HA6dAFQJBEHQ1ACsBQDwgAIAgNppAAC+eR6fXwL+hgewk3J+0pZ4WmO6zu50uHken18C/oYHsJNyftKWbloDpuvsToaEPwYAQCATuoRtAUSIEABoAAAAAAAAajMAAASrBQAgAXB8H6EQUgoh9Yq5sakhAAC8QgEcAJDKNABMATAAOBQgAzQQAACQbBQAflmeHh+C3/9sdtJwfn7fRkWMIGPb/Qgvy9PjQ/D7n81OGs7P79uoiBFkbLsfIe8rAAAWugQBECEAAFAAAAAAAACaGQAAImoXAAAIAHLi+8WJQAohjTVaY4sSAAAAALVlACgBGKUJgFcAfABOcAAAEDgmAD45Hp9fgt//cf0QhufPr0HcITD9m93vksnx+PwS/P6P64cwPH9+DeIOgenf7H6X8L4EAMAI6BIkAIFAIAAAKAAAAAAAAE0AANRBHRUAAAKAnJxrEIDAWKOYWRAAAAAAOCoAEAA1AJwogAIAgGJEAQC2GO79S/Ab/sXu/v3p+V4lZLqDvXtxMdz7l+A3/Ivd/fvT871KyHQHe/ci122/3+/zBGSqWxMBRRwDyKzWW48IAAKBQAgAXIcBAAAAAIBpdXSwGKJisTnYrVbTqlprDWotKiKqaq0RjArWGAEARMUKAMDdxJEkSZIkKRIogAA4gDXwf4QAIAYAxANIABpMAwC8kcf/e7A4ejjjWvJev5HH/3uwOHo441ryXh+MDFEruRmhnmoiJDCSOwDGWmusgBURo4CBaWdt/VpGAAC8kZf/l8ECV6GRtS75Tb+Rl/+XwQJXoZG1LvlNH4DBzUi1FUQCo8cBwGqzGDZRCxi1GAHFjkqtl13WEwC8kUf/pwA/qtCIUYEOmH4jj/5PAX5UoRGjAh0wfQDSwUClFkICYwjApo5qdbQpasSgCphisdr8dS53DLyNu/97sNio0AheSv6u3sbd/z1YbFRoBC8lf1cb3AzKGggJjCUAQVWNCIg4mI52U63VDtumGRDt8AC0jXf/rwL8rsLGSn7TbePd/6sAv6uwsZLf9MGIDHUEN4OoF5HAaHEHUIy1KqAiRlHAsJpirzm3ckQBALyNx/8XwcKpQiN5lPxfv43H/xfBwqlCI3mU/F8fgD5uDkBIYCQHAJvVrg6GmKAAqN1Qh701AlWYImiJBACkjZf/FwGuqzC8AB28Thsv/y8CXFdheAE6eH02hRpV3AzKuogERo8DgBGDioCqMSoKqA07Qcl+RU8AtIkX/1fBouWhEbAAHVDZJl78XwWLlodGwAJ0QOUBaDsYQk09iAQBqOEAYBh2cTANA6yqsQYQEPHvc6GGtABciqXnEOpnABoh81IsPYdQPwPQCJkbh/SJhEQAKoYNrO2ww4phpwWNbqGmjZ122qgFB2AV23b1+FQBlKJ3v3f7/L0CioHbpejd790+f6+AYuD2QdJyYwAIZCIw1VQHi+GArOivB0SwZQFIYcGC1MvgjANUxFqUlQJ6mU7Ej4BAAHTqh/0gjgozSn5LkukynYgfAYEA6NQP+0EcFWaU/JYk0832er1er9fr9Xo9ngGhRgIAAIXAxwAiK9XayACSj6FSk5EAAAQCYww0AADcBQAAiFocxGqz26wW01DAMA3TYrXZHRwcbVajAqhVFTUqClABKirWGjVixVqjChhjRUVFRQVASCGM0AsppJifnweIhhHLAIACgHsXAABZluVITAUw4ACgAgEyNA8AAFG7CAIwAMHaVAAAAH5pro8fwe9/rcksxke/Hx/WmBFUvD5VZI6X5vr4Efz+15rMYnz0+/FhjRlBxetTReaI5A8g1FNNAGRtJEAaAcRdggRuEIFAYAzABwCAGwQAAACsWmMUAACsEQMAYDcNAQAAANRUBwUAAIgZCDAAZwOAYiAaUwAAAIADBx4AZEiAEAAAAEciAHAA0QAAAAA+aR6fn4Lf/1k79zDWRfxkLY3Q/j4BwXLSPD4/Bb//s3buYayL+MlaGqH9fQKCJVJvQKipBdgBUuIuQQAaBEBgjIECAMBcBQBAFcCqWFUAAEWxA6AAIHbDQQAAAExbACiA2DIFAADgLACQSMQAAAAYADCQgIGzAADAYQwAaMArAAD+GFY+/xcBv8Px4X4Hfy3+yZ7oRlCR1z5GfAwrn/+LgN/h+HC/g78W/2RPdCOoyGsfIyL1BlDUCyCAZKFL0ANuEAAwxkADAMANAgCAAmoQiwUAAEc1DAAAAJvVEAAAAMMOBQAghkMAAACaB6AQMyoAAAAAAw4MIAAAgG0BgANwBAAAAL741c8/gu9w+86s7qtbdy8KawSV+AzYR4QsfvXzj+A73L4zq/vq1t2LwhpBJT4D9hEhSP4AyHoBQI0ASBHcJUhAgwgADAD8AABwgwAAoICCWGMBABA1agEAADUcVQEAAGJEDACA2EYBAADaCQAAGgkAAAAAHEAgQwAAAMS2AkADUBQAAAB+2E3Pb8Hv//gP93D/Xkfd2Rkwgoqf+bTdEA676fkt+P0f/+Ee7t/rqDs7A0ZQ8TOfthsCki/YBMkI6AI3iAAEBgwUAAA0CAAAAKiYjoYCAOAYoQ0AAGDFLpYCABDGDAAAQAEAwMQaAFCIGQoAAAAwOABwGDgDAACBYwIARAAAAAD+t5Xvv4Lf/7qDc9yvLD/PNYJKfJIKBfG3le+/gt//uoNz3K8sP881gkp8kgoFgdQbkOqWAZgFUgTzJ0CdBHCDCAQCYwz8AABwgwAAIqoCRsACACBY1AIAACBYMQAAgBp2ogAAVq0NAAAArgEAoHkIxAgAAAAAFEqgBABKoQADcAAAAIhYWwWACYAoAAAAvpeVj7+C3//SyZjerzx1x4fWCHt/qmAMe1n5+Cv4/S+djOn9ylN3fGiNsPenCsaA1BuQagFIII0ABHcJ0wc0iEAgEWMMNAAA3CAAAABgxIoBAABshmkCACKmCgAAAICjYQAAAGDaCAAA7QAAAI0aAAAAwIENDwAAlIABAygAAIIdCgAHQAQAAAB+Z433b8Hvv2onVP9+q8v1HhlBlfOJ7APBO2u8fwt+/1U7ofr3W12u98gIqpxPZB8I0j6AVLcAALUSIJHgLkECGkQgEFzFGGgAAJirAAAAgBGMEQAAFGsMAACgpjgoABAAAGxMAQCuDwCgnQAAnBURAAAAgAEHEQAALsBAFM4AACBqywIAJuANAD5H9Y9fgu9/yV1qJfSZ5+5sDRlh/+vsowPnqP7xS/D9L7lLrYQ+89ydrSEj7H+dfXQg7YINkBJ3CQLQBSCQiDEGfgAAmKsAAACAKaaDCAAAYmIIAGAAAGwsBAAAAKt2WigAgNhWBQAAOBsAPNsqAAAAIPABAEAsRCEAHAAAAJhqDQABuAEAHif199+C31/d2hh+fu8PqDtbz0ZQxXP2ATFO6u+/Bb+/urUx/PzeH1B3tp6NoIrn7AMiUm8AZR2AHSCZ4C6gC0AgMMbADwAAcxUAAABQjEEAABQxHAEAAEStAQQAxxQAAAAXAACAAgBWrNgJALZEAQAAwEAKABIIEIA8AQAAVG1bAYAMvAYA/pWc16fg/8tu50zPV9cnNQpU/sYI7edHvH1E8Ss5r0/B/5fdzpmer65PahSo/I0R2s+PePuIIlJvAFEPwAaQOLnKnwD1AqBLCUAAEhvEGBphAQDA1QYBAABAAGsFAABxcLBYAAQA1BixAKgKAAAAAICKFQAAAMOWKaiI8L0AAAAAAIhEogAAAADAdwGGCwAAAAAgCpBAAMBEAAAACAAgRgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC+ddS3P4Lf8NJtpBN+defcZZKMsEfZRxduHfXtj+A3vHQb6YRf3Tl3mSQj7FH20YVIPWACgBoBkA5qAMDHVf4EVKMCILoUAEAiEhtsEKAHAMANAgAAgAhiMQUAAMBaAAVR1AAAAAAYawBAUQAAAAAAO8QSFAEAuGICAAAAAPAK4OAVAGEAAAAAAEQBAIAoAABEQgAAAACwsKtdASADxAwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH5V3I+b4Pe7fMy4g3099/uNzd8UI+zv1G4XuSrux03w+10+ZtzBvp77/cbmb4oR9ndqt4sgdcEAybML/gSokwB0KQGARCRCgwCNIAEAwA0CAAAAgtoUAABEBAHAEAEAAAAAwOIgAAAA1jYKqAAAWFhbCiAAQRAVAAAAAABANBoBAAAAAADAwgaAC4APAAAAIAoAQBAzBAAAAkAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPjVsy1vwG9Y+Tg6hvvtU/RrKjdC+Rnr26SBTw7a8Bb9h7ePkEOq7T9WvodwI7WukZ58OgtQFA6T4cZU/AUVtFYAGAaBBAOA6DAAAcIMAAACAqE0VAABUFAUAADAwHAEAAMQ2gAIAYIdpFQBALexqKgAAAMBnDQAAgAkA30UMAwAAAAAAADGA7wKADBAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+FJyXt+A/VN7urniu+Vnxc+6nEeynkdgXlDwF5+Ut+A+Vt7srnmt+Vvyc+2kE+2kk9gUlSN0wCSSQ6hvkT0DWFgA0CEhEMgAA12EAAMDVBgEAAADBdFAAAMCmpgmgAKCCsQIAAGCKAQAAYNo2AAVA7TQUAAAAAAAgYmEDAAAAAAAAEUNMAQAAAHwAEAEAAAAIAAACAIgRAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL70m/a3gIBX3tThucSnu1ieHzdC+x6V7cs7WfpN+1tAwCtv6vBc4tNdLM+PG6F9j8r25Z0gtYQEkpFqkD8BWScAwAAAAMB1EAAA4AYBAAAAdTSsAAIABjAAAACYhgkAAGAbCwAAAMDargAAMRUBAAAbAAAADAAAAEUNAkAIABkgZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnvTztx8B/4Phjju009L9fT4yQvs/CrIvD0z6+duPgP/BcMcd2mnp/j4fGaH9HwXZlwcidYEEaQSYXO0SLAADAABADwCAGwQAAADAYqIAiCkIAAAAgIODVRQAALBtDQAAAJY2FgqgAAAAQDQaAQAAAAC+FgUAiAAAAACApY1dACAARKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACe9HvNh+B/5s2jF2J5zn6j/z56RmiPSvYlxaTfaz4E/zNvHr0Qy3P2G/330TNCe1SyLykixQ8pJDfInwD1AqBBAAAAaIQFAABuEAAAAKxYsQAAAGBYAAAAsAsAAEAIAICNYQEAgGHLRgAAiAEAAEAIAABABIgRAgAAAEAEAADgAMIYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ70e5+74Hsub/rLHvPJfqN1EHEjVJTYvqCY9Hufu+B7Lm/6yx7zyX6jdRBxI1SU2L6giFSP1GyQPwG1RQ0AXQAAAABSAAC4QQAAADAGAwAAAHYAAAAARGMKAACwtIsIAIBhY6kAAAAAEAEgoigAAEAIAAAQiUbBxgIAAAAAACzstASABhDEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnvT7XmfB/4wP3ZTKfla/sfvRM3r+fC2QpN/3Ogv+Z3zoplT2s/qN3Y+e0fPna4EgtYQAkpHcIH8C1EkAugAAAACkAACgCwAAAEDUNAAUAIzBGgAAAFsAAAAA2JgCABDFAADEBAAAAAAAAKIRsGUVAAAAAACssQEAsAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACe9LteL4LvtDfzOGWuu1jfa6PnvxrGpN/1ehF8p72Zxylz3cX6Xhs9/9UwwobU5Cp/AoraEoAuAAAAACkAAGgQAAAA1IooAACAip0iAABAJEZUAAJsTGsAAAAAAACiRAAAAAAAAmysAQAAAAAAaxsAgJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ70+95nwW+zm65oYz/nI/P8t1H+WU1g0u97nwW/zW66oo39nI/M899G+Wc1gUhtSCEZuoRtA7oAAAAApAAAoEEAAAAwbXZRAAAAbAMAAIBiYwEAABAjGjUAgNpFBACAGAAAAIAtqwAAAAAAgC0AAGIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnvQrzy/Bt/abRinv1Sh4W4w+/KgFTPqV55fgW/tNo5T3ahS8LUYfftQCQo8UQJcgAF0AAAAAAABAgwAAACCmRQQAAADCGAAAABZ2RQEADDtMAACwbQsAAACAmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACe9Pu4rIJv2J2zaOW9jh87srfFqN81xaTfx2UVfMPunEUr73X82JG9LUb9rikCP6SQDF3CLKALAAAAAAAAAAAAAAAHOwAAEAAAoHaKAgBYW7UKAABRAAAAwNoGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ70e14Owdd0Z9xieq/jx0nONXp/V1NM+j0vh+BrujNuMb3X8eMk5xq9v6spwkQaCQC6BAnoAgAAAAAAAAAAAMAEAAAAQFFRAAAAIIIAACCMRgwQ2tgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnvS7X7eCLzB26ldr7yfjx8nE21r5f00x6Xe/bgVfYOzUr9beT8aPk4m3tfL/miLwIQXQJWwLwFUAAAAAAAAAAAAAwLADAAAZAAAQjQQCALCxag0AAD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACe9Hscp+APPN9J2f1+i6JAXebVFJN+j+MU/IHnOym7329RFKjLvJoirRHbAw2gS9gekNwFAAAAAAAAAAAAKqJqcVCLYZgYigqmITY1bKgAcBhWsbaxtIvaWFjYiGESGJkgZgw7sLWZ6gY1bKwtAQAAAAAAHMNOu9gYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; + //关闭 + public static final String switch_off= "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"; + //开启 折叠 + public static final String switch_on_collapse= "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"; + //关闭 折叠 + public static final String switch_off_collapse= "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"; + //通知信息 + public static final String inform_info= "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KcYYY8w5pxRjjDHmnGOMMcYYc84xxhhjjDnnGGOMMcacc84xxhhjzjnnGGOMMeecc4wxxpgAAKACBwCAABtFNicYCSo0ZCUAEA4AABjDlHPOQSgllQohxiB0UEpKrVUIMQYhhFJSai1qzjkIIZSSUmvRc85BCKGUlFqLqoVQSiklpdZadC10UkpJqbUYo5QihJBSSq21GJ0TIYSSUmotxuacjKWk1FqMMTbnZCwlpdZijLE555xrrbUWY63NOedcaym2GGttzjmne2wx1lhrc845n1uLrcZaCwAweXAAgEqwcYaVpLPC0eBCQ1YCALkBAIxSjDHmnHPOOeecc85JpRhzzjkIIYQQQgghlEox5pxzEEIIIYQQQigZc845ByGEEEIIIYRQSumccxBCCCGEEEIIoZTSOecghBBCCCGEEEIppXPOQQghhBBCCCGEUkoIIYQQQgghhBBCCKWUUkIIIYQQQgghhBBKKaWEEEIIIYQQQgghlFJKCSGEEEIIIYQQQiillBJCCCGEEEIIJYRQSimllBBCCKGEEEIIoZRSSikhhFJKKSGEEEIppZRSQiihhBBCCCGUUkoppZQSQikhhBBCCKWUUkoppZRSQgghhBBKKaWUUkoppYRQQgghlFJKKaWUUkIoJYQSQiillFJKKaWEUEIIIYRQSimllFJKCSGEEkIIoQAAoAMHAIAAIyotxE4zrjwCRxQyTECFhqwEANICAABDrLXWWmuttdZaaw1S1lprrbXWWmuttUYpa6211lprrbXWWmuptdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lpLKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFIB2AUbDoDRE0YSUmcZVhpx4wkYIpBCQ1YCAGkBAIAxjDHmGHQQSkkppQoh5yCETkIqrcUWY4SQcxBCKCWl1mKLMXgOQgghlNJSbDHGWDwHIYQQUmotxhhjDLKFUEopKbXWYoy1FtlCKKWUlFqLMdZagzGmlJJSaq3VWGOsxRgTSkiptdZizLXWYnysJaXUYoyxxlhrMca2FFKJLcZYa421GGGMaq3FWGOtsdZajDHClRZiirXWWnMtRghjc4sx1lhrrrkWYYzRuZVaao2x1lqLL8YYYWusNcZaa87FGCOEsLW2GmvNNddijDHGCB9jrLXW3HMxxhhjhJAxxhprzrkAgNwIBwDEBSMJqbMMK4248QQMEUihIasAgBgAgCEAhGKyAQCACQ4AAAFWsCuztGqjuKmTvOiDwCd0xGZkyKVUzORE0CM11GIl2KEV3OAFYKEhKwEAMgAAxFnNOcecK+SktdhqLBVSDlKKMXbIIOUkxVoyZBCD1GLqFDKIQWqpdAwZBCXGVDqFDINcYyuhYw5aq7GlEjoIAACAIADAQITMBAIFUGAgAwAOEBKkAIDCAkPHcBEQkEvIKDAoHBPOSacNAEAQIjNEImIxSEyoBoqK6QBgcYEhHwAyNDbSLi6gywAXdHHXgRCCEIQgFgdQQAIOTrjhiTc84QYn6BSVOhAAAAAAAAgAeAAASDaAiGhm5jg6PD5AQkRGSEpMTlBSVAQAAAAAABAAPgAAkhUgIpqZOY4Ojw+QEJERkhKTE5QUlQAAQAABAAAAABBAAAICAgAAAAAAAQAAAAICT2dnUwAAQK4AAAAAAACNjVdGAgAAAOsMIbKZvMuQsqif////C///xv//3P///xr///+mtamm////D///r///3v///yf///8/////Tf///5X///+j////t////6j///+/////rf///8j///+z///5///k///J///c///l///s///Q///n///y///W///b///f///n///e///j///S///f///W///e///g///T///Y///T///dfPVil8ibs9BxddSzK8iX38Ad7uMvtoZxhb+870ab+jmbWraV02fMlmpmlQyT0aa5Ynu1//xx/SrPL1ZdZ7UimPgdGfzH1LNN7TbNPlPzPWuV9Lwytvetqm2rZ8n396zQYjVT8eiMoPtM0Gvf5+slxfeUQ2O+y+V4pXEgLhB7g/2Jq15q+0v2JRPme7u2I5X5lUuZBN+uvUoEzZ0XIoscP2y9j+sieF6rBK+q7kmQ4o08D6q99TJCvJZSogq09MBRF6rS/COuUq70kLNWHil+qKirG41Vpd0y9sifTrVZe/Fe41mf9xMYv/8LqWOuk3EM5Ck3+njF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"; + //通知信息 GTA5 + public static final String inform_info_gta5= "SUQzBAAAAAA1E1REUkMAAAASAAADMjAyMy0wMS0wMSAwMjoxNwBQUklWAAA0SgAAWE1QADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDcuMS1jMDAwIDc5LjRkMmY1OTcsIDIwMjEvMDkvMDEtMjA6NTE6MjIgICAgICAgICI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgIHhtbG5zOnhtcERNPSJodHRwOi8vbnMuYWRvYmUuY29tL3htcC8xLjAvRHluYW1pY01lZGlhLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgeG1sbnM6Y3JlYXRvckF0b209Imh0dHA6Ly9ucy5hZG9iZS5jb20vY3JlYXRvckF0b20vMS4wLyIKICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpiYjEwNGVjYS03NDM1LTc1NDAtODgxMy02MzZiYTNlMGQzOWEiCiAgIHhtcE1NOkRvY3VtZW50SUQ9IjQ4NzM4MDc2LTExNmItYjA1Ni0wNDgyLThjMjQwMDAwMDA0YiIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjVmZjAxMjA5LTFmNmEtM2M0OC1hNDFmLTQ1ZDZkYWMyNzdhZiIKICAgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMy0wMS0wMVQwMjoxNzo1NCswODowMCIKICAgeG1wOk1vZGlmeURhdGU9IjIwMjMtMDEtMDFUMDI6MTc6NTQrMDg6MDAiCiAgIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUHJlbWllcmUgUHJvIDIwMjIuMCAoV2luZG93cykiCiAgIHhtcDpDcmVhdGVEYXRlPSIyMDIzLTAxLTAxVDAyOjE3OjI0KzA4OjAwIgogICB4bXBETTphdWRpb1NhbXBsZVJhdGU9Ii0xIgogICB4bXBETTphdWRpb1NhbXBsZVR5cGU9IjE2SW50IgogICB4bXBETTphdWRpb0NoYW5uZWxUeXBlPSJTdGVyZW8iCiAgIHhtcERNOnN0YXJ0VGltZVNjYWxlPSI2MCIKICAgeG1wRE06c3RhcnRUaW1lU2FtcGxlU2l6ZT0iMSIKICAgZGM6Zm9ybWF0PSJNUDMiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0iMmY2YjRlMWItYWFjYS0zNDZlLWQ1N2ItZDFjMDAwMDAwMDc4IgogICAgICBzdEV2dDp3aGVuPSIyMDIzLTAxLTAxVDAyOjE3OjU0KzA4OjAwIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQcmVtaWVyZSBQcm8gMjAyMi4wIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIvPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjA0NzViYjJiLWYxOTctMTg0Yi04M2VjLWU2YWRiNjQ5ZThkNyIKICAgICAgc3RFdnQ6d2hlbj0iMjAyMy0wMS0wMVQwMjoxNzo1NCswODowMCIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUHJlbWllcmUgUHJvIDIwMjIuMCAoV2luZG93cykiLz4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NzZhZTg1OWEtOGZkMy1lOTQxLWFiNGUtNmVlMjVhMGQzYjkzIgogICAgICBzdEV2dDp3aGVuPSIyMDIzLTAxLTAxVDAyOjE3OjU0KzA4OjAwIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQcmVtaWVyZSBQcm8gMjAyMi4wIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIvPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpiYjEwNGVjYS03NDM1LTc1NDAtODgxMy02MzZiYTNlMGQzOWEiCiAgICAgIHN0RXZ0OndoZW49IjIwMjMtMDEtMDFUMDI6MTc6NTQrMDg6MDAiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFByZW1pZXJlIFBybyAyMDIyLjAgKFdpbmRvd3MpIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvbWV0YWRhdGEiLz4KICAgIDwvcmRmOlNlcT4KICAgPC94bXBNTTpIaXN0b3J5PgogICA8eG1wTU06SW5ncmVkaWVudHM+CiAgICA8cmRmOkJhZz4KICAgICA8cmRmOmxpCiAgICAgIHN0UmVmOmluc3RhbmNlSUQ9IjI0MDYyNWE4LTA4ODMtMzZjMS0wZDU2LTc5OGIwMDAwMDBiNiIKICAgICAgc3RSZWY6ZG9jdW1lbnRJRD0iZGNjMTZlNTctN2UxMC1iYWMyLTY2ZmMtMjk5ODAwMDAwMDg5IgogICAgICBzdFJlZjpmcm9tUGFydD0idGltZToxNDc1Mzk0ODQ1OTA0MGYyNTQwMTYwMDAwMDBkMzMwMjE3NDk3NzkyZjI1NDAxNjAwMDAwMCIKICAgICAgc3RSZWY6dG9QYXJ0PSJ0aW1lOjBkMzMwMjE3NDk3NzkyZjI1NDAxNjAwMDAwMCIKICAgICAgc3RSZWY6ZmlsZVBhdGg9IkdyYW5kIFRoZWZ0IEF1dG8gViAyMDIzLjAxLjAxIC0gMDEuNDUuNTAuMDIubXA0IgogICAgICBzdFJlZjptYXNrTWFya2Vycz0iTm9uZSIvPgogICAgPC9yZGY6QmFnPgogICA8L3htcE1NOkluZ3JlZGllbnRzPgogICA8eG1wTU06UGFudHJ5PgogICAgPHJkZjpCYWc+CiAgICAgPHJkZjpsaT4KICAgICAgPHJkZjpEZXNjcmlwdGlvbgogICAgICAgeG1wOkNyZWF0ZURhdGU9IjIwMjItMTItMzFUMTc6NDY6NTZaIgogICAgICAgeG1wOk1vZGlmeURhdGU9IjIwMjMtMDEtMDFUMDE6NTQ6MDErMDg6MDAiCiAgICAgICB4bXA6TWV0YWRhdGFEYXRlPSIyMDIzLTAxLTAxVDAxOjU0OjAxKzA4OjAwIgogICAgICAgeG1wRE06cmVsZWFzZURhdGU9IjIwMjIiCiAgICAgICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICAgICAgeG1wTU06SW5zdGFuY2VJRD0iMjQwNjI1YTgtMDg4My0zNmMxLTBkNTYtNzk4YjAwMDAwMGI2IgogICAgICAgeG1wTU06RG9jdW1lbnRJRD0iZGNjMTZlNTctN2UxMC1iYWMyLTY2ZmMtMjk5ODAwMDAwMDg5IgogICAgICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmI0Y2Q5M2UyLTU4NDUtMmI0OS1hNzEwLTNkOWRlNjZkMDYzMCI+CiAgICAgIDx4bXBETTpkdXJhdGlvbgogICAgICAgeG1wRE06dmFsdWU9IjY0NjE2IgogICAgICAgeG1wRE06c2NhbGU9IjEvMTAwMCIvPgogICAgICA8eG1wTU06SGlzdG9yeT4KICAgICAgIDxyZGY6U2VxPgogICAgICAgIDxyZGY6bGkKICAgICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0iMjQwNjI1YTgtMDg4My0zNmMxLTBkNTYtNzk4YjAwMDAwMGI2IgogICAgICAgICBzdEV2dDp3aGVuPSIyMDIzLTAxLTAxVDAxOjU0OjAxKzA4OjAwIgogICAgICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQcmVtaWVyZSBQcm8gMjAyMi4wIChXaW5kb3dzKSIKICAgICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIvPgogICAgICAgPC9yZGY6U2VxPgogICAgICA8L3htcE1NOkhpc3Rvcnk+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICAgIDwvcmRmOmxpPgogICAgPC9yZGY6QmFnPgogICA8L3htcE1NOlBhbnRyeT4KICAgPHhtcE1NOkRlcml2ZWRGcm9tCiAgICBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA0NzViYjJiLWYxOTctMTg0Yi04M2VjLWU2YWRiNjQ5ZThkNyIKICAgIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDQ3NWJiMmItZjE5Ny0xODRiLTgzZWMtZTZhZGI2NDllOGQ3IgogICAgc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjA0NzViYjJiLWYxOTctMTg0Yi04M2VjLWU2YWRiNjQ5ZThkNyIvPgogICA8Y3JlYXRvckF0b206d2luZG93c0F0b20KICAgIGNyZWF0b3JBdG9tOmV4dGVuc2lvbj0iLnBycHJvaiIKICAgIGNyZWF0b3JBdG9tOmludm9jYXRpb25GbGFncz0iL0wiCiAgICBjcmVhdG9yQXRvbTp1bmNQcm9qZWN0UGF0aD0iXFw/XEM6XFVzZXJzXHNoaXhpXERvY3VtZW50c1xBZG9iZVxQcmVtaWVyZSBQcm9cMjIuMFzmnKrlkb3lkI0ucHJwcm9qIi8+CiAgIDxjcmVhdG9yQXRvbTptYWNBdG9tCiAgICBjcmVhdG9yQXRvbTphcHBsaWNhdGlvbkNvZGU9IjEzNDc0NDk0NTUiCiAgICBjcmVhdG9yQXRvbTppbnZvY2F0aW9uQXBwbGVFdmVudD0iMTEyOTQ2ODAxOCIvPgogICA8eG1wRE06cHJvamVjdFJlZgogICAgeG1wRE06dHlwZT0ibW92aWUiLz4KICAgPHhtcERNOmR1cmF0aW9uCiAgICB4bXBETTp2YWx1ZT0iMzgiCiAgICB4bXBETTpzY2FsZT0iMTAwMS8zMDAwMCIvPgogICA8eG1wRE06c3RhcnRUaW1lY29kZQogICAgeG1wRE06dGltZUZvcm1hdD0iMjk5N0Ryb3BUaW1lY29kZSIKICAgIHhtcERNOnRpbWVWYWx1ZT0iMDA7MDA7MDA7MDAiLz4KICAgPHhtcERNOmFsdFRpbWVjb2RlCiAgICB4bXBETTp0aW1lVmFsdWU9IjAwOzAwOzAwOzAwIgogICAgeG1wRE06dGltZUZvcm1hdD0iMjk5N0Ryb3BUaW1lY29kZSIvPgogIDwvcmRmOkRlc2NyaXB0aW9uPgogPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSJ3Ij8+AFRTU0UAAAAPAAADTGF2ZjU4LjQ1LjEwMAAAAAAAAAAAAAAA//uUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAxAABLAAAKCg8PFBQZGR4eIyMoKC4uMzM4OD09QkJHR0xMUVFXV1xcYWFmZmtrcHB1dXp6gICFhYWKio+PlJSZmZ6eo6OoqK6us7O4uL29wsLHx8zM0dHX19zc4eHm5uvr8PD19fr6//8AAAAATGF2ZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASwDM4SKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//uUYP+AChkDxyHvCBgFYEjEAEABAbwPGoPgQGgVgSLQAYAE////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ggAAABbjRAAAhCzALoMU8aiFCQAAAAhNkgAAQCgcLOAteEkv//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACikDxqE4CBgEwBjUAAABAawPHIe8QGgTAGOQAAAE//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8EAAAACGUJIAAGDvADpdAGjqCUEAAAASRJEgAADBoBE1wS//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACiADRqFvYAoFgEi0AEABAagVGIwMYmAUgCNQAAAE//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////kgAAADI2yQAAKAPCfDVl9j6MpxJEEEpACChF3FDhsE9fVkP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACk0DxqApCBoFABjkBAABQYwPGoe8IGgDgGNAEAAF/////////////////////////////////////////////////////////////////////////////////////////////BAAAAEio2mkknv3cAVH7cSkj8ev3qeR/qcEIzkFDTuruYR+2dNCezqjJ0bX6MSd0///97dNX179avV62SvVb1PvHkN+qf7dQiASKyCv/Jny7d7rn4fsgSD5MHwGTQ81UU///13CEv7jiDyE9+7UM1Z9qRQuRtpJVW0u9LwkzkgF6NaajCnW0pQ7DkMDn6ekaWdzbFI4eBV5pGQX7PHj0UbnuAwMCseRYkXO479/Hte/owKxWPHkfFHsM/ydqM3AC8K9bQw0GTN8Xv/f/5xSmMw2O+GOP4mI8N/i8OFI2QKTaw1U3ePDtCV8feIETG53jzXz4mKyv3LbDmjcOJHT3wXEfosLnHroSkr/8/kIeycdTUytO8fL//uUYP+AB0YDRyEvEAgFIAjEAAABCFEnHWwITYCugCOkAAAAppE7C96uysMZiszCuhiDTdLuK1/7C/l++YZtFuectv5HB87R29RARwQw2cnLEKA8g5lFXnAIKTzOjCOPuYdlb41JI9IgGCCSyEQidtMDIfg6FhkQBggWbVGZbAYqQDYA39CB7nmbMGveFAlTZGQwIBgYFTCwTEYCJgekAhAKgEx8YTOYiBACWMYgILDXXLYGAAEBQAkqBACKgJuBgcBI0A4Bs7ZOYCAxiQYjKKYEYNDgWBqWo6UEkV9TphYMBAgMnjMQiIxwFAEIzBQPMPCkQjMfqRgIIvsoNHTBQhPYIoSJC0VXw4AQ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rSnFptPKRmaBgbnTIrgIsgSajMFM3NEjWumy3qs7OowBCSBFWOoUKatTv60lqcwC2wLNUne/XWqz3rpsDUQNp///+s////5w9/////////////uUYLuAA+ZayWszo2AFwAjkAAABT4VrG4zCjYAVgSMQAYAE////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ggAAACSMRLIACsyhNg+oB4kXSQ1Qg0hW0//tegMHGT7Me6nzJ7mMca7gkhDQVmy3Uq9uvZ3rUEIQFmS2bWtTX/61C+CgVJX/qf/CYAkl1///1v///5w8CAAAAEh2JNJAU5UsV0A2i4BAAspPThhyXv9P/8FH3tT2607pqCC4mjOv//fXDyA53///jcC4vt//1QyYt16v//rf///zjf////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYOeABoFax+sNo2AFIAjEAAABCjVrG4kqjYATAGMQAAAE//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4IAAAAmM6kaaIAq2ZcRhDTAP0xpnX1gO8ZX//2tQLH516sp6NnU62WqEvFRWytf/31KESCjX///yUE0///8RIt9H8n/8gCAAAAIOAxotEAKyqFwewuHRIktFO4d0Gs///thT73ptauvekwTkiKvav6337C+C6////lIRb///eKwf///+Q///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACIdax+Inm2AGAEjUBEABB+kLH4eeS4AWACMQAAAE/////////////////////8EAAAABHdiTSSbkkjQO4MLekU4Ald7e+Yqdo5+cnNv9O2+L7LHG32DAeB4dEMtjgFAngBxpYd81yNo0tdcBLskKmD2OHA94dnWYl+0NW9e7oLEjK74PZQ6joMsiLD4PZRAj7v29bXxwQe/fSKu3Ln8fuIRSbh/KUWK85Xp9UlmV24IJgKTm88tYfz//n/////pql9n///kGAAAFCYpn///+ojb/pGJGEkh4WWr/5CrYmwkbGnN+ussKto+9dSxcK6OrXFiZpE9OcqhP4ym9DUyGpQIhQpQsoJ0uhcp3C1Soi5pelHYtcyMtqy9E1XqqyjJgqfJokAUxfFBoHGX2AAsULVIVIgl4mRlpW8LdJJJ6l8U7C0qVBv0e1LXRVdhFZf6PTFmsstgp3qdyZA+sVjz/U8My2AlAnFq0uOqbLH/3+v/f///+UqjV8Gx///uUYP+ABZpCx2IlkuAFgEi0AEABEjkLH6wzK4BEgOOgEQAA/////////////////////////////////////////////////////////////////////////////////////////////9gAADwk4P///UcirkjK3DeJ9J95ARAU0lRpIhIyzIHyQL2am/VPOb/HLNPyTAjGQ/hAEZnndNpef8J6kHpSOZzO2f8/eoGFIiA7WPv61/9IAABeKixX/91al9fWkwo8y1V0Yh6soJzIs5zYQAbdqKmUrNhRokAk/gQAPQiIdJgTc7rFc1U/klXmGqfOvNgNjzB6hhVaXqUn//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+AB0pDRknvwuIYAEjoBGAABuCrHYwEa0iNkuNgIAko///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8gABPwKP/6/488BHhqdh5q2g2cWG4jlkiQUHPMOJEEIAoDglDyrBX6oGjqMQnP/0Frvru4lwAQEMG///6KzAtEAgAdbC4AghAaVioI/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACO4DR1gvSAAcIBjoAAAAAxQRHWTgYEAlgONUIQAA//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////5IAAAAocSJAAGgiDmECtMGpsAtIAAAfbGmqBgqw8TRT6////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACk8ExiHsAJgE4AjkAAABAYARHIY8QGADgGMAEAAF//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wQAAABLuNIkgDJml/H+DYJs6K6lfsEAAAAdTBxpEEAWCgVJ/Fepg3Jf/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACgYExiMMCJgFIAjEAAABAgQVHIekQmgWgCMQAAAF////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yiAAABjqFlEAADmQcdQdaQ2RidIggAAADtZRtAkgIIS6jqOd6tGYWw3///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+AChIDxyEvEBoF4BjkBAABQcgTGIwkImAWACNQAAAF//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+CAAAABA6aQBAAud4NJMhoSEgaUobJAAAAEIJRokkAOFAUA0AZjEhLGuxj6/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACgkERyDvYBgFwEjEAEABAewTGIekImAXAONQEQAE////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yQAAABsBcbKJIGTMA57qFoi3azGVd+UEAAAATBhNIkgAZR4cEQDBESDXy/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACfoERqEYGBoFwAjUAAABQiATHIw8ImgWgONQEQAE///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9RpEEAbewgQPMAABYmVFyR+tAgAAACCJxooggKDELTYRFoaGwmebL//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACiYExqHmCJoAAAjQAAABAjQVGowkYmgWACMQAAAE//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ggAAAAPFGSSABAeDUCzFPPxBlZn1BMokggQGIhJ/YwD7xp1q6P//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACjUDxyG4CBgFYEi0AGABAfQRGoPgYGgAACXAAAAE///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yQAAABocaQJAGxPwEArXJLCQHY/wEAAAAaRJNEkkAFiSalJNUo7zuI2x///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACgwERqFvSBgFABjkBAABQfAPHIe8IGgXgGMQEAAF//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wSAAAAhKaJJAAsEQTx6xnId7nZAgAAADNNEAAAWIwHSDTBIPsqpUCm//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACh4ERqDYEBoFYBjkAAABAcARGoS8QGgTgGNQAAAF////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wQAAABCDjSIAA0KYDKASDsWbGKiwSAAABlttEAgAQhBhOxltkMT6v/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+AChIExiHpCJgFYAjEAAABAdwVHIewYmAWAGNQAAAF////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wQAAABJONEkgCFcOUC0uTnF30CoIAAAAxKBRokAARQOcsaNqIK////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+AChIDxqHvCBgFIAjEAAABAdARHIa8QGAXAGMQAAAF/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////5JAAAAUtRIgAAUKBWMePcNKCAAAAEAtIgAAeKuhPBqVmF////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACjEDxyBPEBoFYAjkAAABAWwPHIG8QGgTAGNQAAAE////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////5IAAAAWo0SAAKBDFIyzKEWxQIAAAAkRyJEAAEgeA+rClwByf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACisExqHmCJgEwAjkAAABAZAPHIG8QGAUgCNQAAAE/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ggAAAChMoAAAQIQYY++FI0AgAAACJgpEAAAQMTE0J3Q+X////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACi8Dx6EPCBoE4AjUAAABAXQRGoK8wGAVgCNQAAAE///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4IAAAAmVEkSQAoIzw5ZIIZ4V+VAgAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUYP+ACiUDxiDsEBoFIAjEAAABAcQRHIG8QGgQgCNQAAAE//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////uUQP+ACuAAS4AAAAgAAAlwAAABAAABLgAAACAAACXAAAAE//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//uUQP+ACuAAS4AAAAgAAAlwAAABAAABLgAAACAAACXAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + //通知成功 + public static final String inform_success= "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L/zJT727/dtsb7dwtEsgTLpFzl17UeWlZg9XVSzk5glabtsBAqREpQFMUBBQAuLSDkCIEQajq4dCEDYGy3mjIShKPvKohA2EYnPMnJiYrkiwUAgEJRONIkUcajiU+jiRJLXOJEkktNIkSVOaRIkZEIKhqDQaUDQdg0DUFQ7EoalTsGg1ER6Ig7WHYlBVwlBWIgVOlgalga/8RAqCrg7g1EoAIIFAQECChCsiComFal5hELF/IT/+IhC/+L/2QQ//k//wqai//8wh/5qYf/IQsK///5Cmph0YcQmEInGDCmxdTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5Jk7oADhjBH6y9gAFdNiFkcRtpQPKEVLDDHwP81YPAQjzlVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ=="; + //通知错误 + public static final String inform_mistake= "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O1j6I+OToul0uHbkcVqtNQmW0nFmGXC0SQKKEgYgmgtEkacKAzLx2eM3NkkRFAYGYTQWiSNFCgMxPNzcmn+UacWXF4tEkaKFFmJ5ubjtuU7O1Oz1JxpRR8JqSInGlmXG942pb+TizFU05+ioio7PqqW+65ihgYIEDIdn6p/+yKiKR2MVFVDs/ovKZUi83KNONNKPQXNTVO296eI37lGnGiSn//7M7dpZ2Z23P/+3//7zUtNFlHjlTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU="; + //通知警告 + public static final String inform_alert= "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zrn4FK4FQ4MIf7LThMwIG1c3LlZxcYm/CubqpBmYFSZgdMSFLI4f4do4uaqmRdG+jpMYfJLo3tlItqArFMTMTBrKvZiP4Xu63///7Yr66gB1AWUKAl/QymMBCnobhnCphF85vKuJh5Pk+i/hDyl/lEtU8lxE+twiiJMSxDLZH4lreWfJthqHeVcRJKLEIK9DaAQE/QtHwwo1DP5i1L/MbqFMOPOXEsSuVUHdxIKRKd1A1W6dKnmHVna7eoKPyqJGTzvwZkWqaoYlgsd09MFBR+ykf3+kKCgxBl+y0m/l/6hqGB1OWGXy/89goJxJzuykn0ooj/plREhP7BqxJLlUpJLKTY9LTe///+/+7Jb/+3JE9w/yXCg+getBwEoEh8A8w04JrMTyAphsSTGU3cAwDRGKTJaaZv0VYjKCfQj/6MmrlMq//8pkcqOUMJBUi7FkVJ/qSEv/FuoW1p4xvWKEgKx1TEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7cGTqDoHkMDmIQRVAOoQHIAAiFgnArqgBhGhIpo9XWBAKDFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+3JkdI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7cGR1D/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+3JkdI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7cGR1D/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+3JkdI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7cGR1D/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+3JkdI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ=="; + //打开窗口 + public static final String window_on= "SUQzBAAAAAADVVRFTkMAAAANAAADQW1hZGV1cyBQcm8AUFJJVgAAAw0AAEFtYWRldXMgSUkgMy41AG1hcnUAAAAYAAAAAQAAAAAAIQAMVGVtcG86IDEyMC4wbWFybgAAAUVicGxpc3QwMNQBAgMEBQYiI1gkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRvcBIAAYagpgcIDhYXHlUkbnVsbNIJCgsNWk5TLm9iamVjdHNWJGNsYXNzoQyAAoAF1A8QEQoSExQVVUhTUG9zV0hTQ29sb3JWSFNOYW1lEAAQAIADgARcVGVtcG86IDEyMC4w0hgZGhtaJGNsYXNzbmFtZVgkY2xhc3Nlc1hIU01hcmtlcqIcHVhIU01hcmtlclhOU09iamVjdNIYGR8gV05TQXJyYXmiIR1XTlNBcnJheV8QD05TS2V5ZWRBcmNoaXZlctEkJVRyb290gAEIERojLTI3PkRJVFtdX2FqcHh/gYOFh5SZpK22ucLL0Njb4/X4/QAAAAAAAAEBAAAAAAAAACYAAAAAAAAAAAAAAAAAAAD/AG9zcnQAAAAIQOWIgAAAAABUU1NFAAAAEwAAA1VQWVVOIFRyYW5zY29kaW5nAAAAAAAAAAAAAAD/+5DAAAAAAAAAAAAAAAAAAAAAAABJbmZvAAAADwAAAAoAABH0AC4uLi4uLi4uLkVFRUVFRUVFRUVdXV1dXV1dXV1ddHR0dHR0dHR0dIuLi4uLi4uLi4uioqKioqKioqKiurq6urq6urq6utHR0dHR0dHR0dHo6Ojo6Ojo6Ojo/////////////wAAAABMYXZjNTguMzUAAAAAAAAiTQAAAAAkA4oAAAAAAAAR9IFTPTsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+5DEAAAUoPsyVZkACzCmZos9wAAAAGNpQIQFQzRbN+E3WTRJAwaKaKCxGcOQ5DOGuRSViFAxADfAMEA2gDiANgDGAm8DBANCBswFogZYEFBQAuQWQJTFBi5xzyLkXIuT5fJwuFwuFwihFC4yDJl8vm6aaZcLiCHqTTfWm9NOpBBD/6CDf6aaab00FmZFyLkXL6b//w8AAAAzAAAAAADw8PDwwAAAAADw8PDwwAAAAADw8PDwwAAABycAAEDCAxqSxTCDC+MAFL8xlAOTBPTzMIQD0wGAEjAuA7HQNBoEoKgFFALYBAIMAwDt+tO1KxAAjKKGayYFFqmIjO4SSF6BcAiWliUuCIjK5QgAT+SzR4lExViVJ3O8g6xJHllKwExncyxsXL1TSu4bYLI1ho/U7Yu3s+5038rM8ljvva/rtUN+1vLL+8/8997EZZDdHON8QhFfT/f93e7pACUoMN/+/9VFAlxUunZmWZoaxJ/o1ul1+7+N7///5/3/dhIGhKMPWf//54aqAFj3ySbm32+2tskSQAAtVARfC9TBT/MA0M3/+5LEDQAZGP1Juc0AEyYzLjc3NEKOCzEJ/NShQwMhQYDjABJDjoYHCQYEDIxrMEBMwwRwAHYBHLdCIotUCEwOxlb8g4DSTCTTMXMW0JGn0LSqpLAO0iIYg05ZjAJgCxhQCA9gSDS708HZTdhxJMs4OA4KLniSJH1OeVPiPEJUzNz1M2zJessLjp3MCauzxg0MPvOSemjD7TU/EKadxj7tPRAVi1SyvPvb+O1kkTGxj+esuxAeK4bq7z/GAmW6kUdV2gggAKW3zaW9PFWSNSRaAYZnxsnKoyTKb4pso2lA4igPBoWAmrp0oE26RdgKRhAhkhMywR4dEWSLkUIoHEBtIz4ZeDOwsdC8BBYLrG4541hOAgIOEQCASkNWEuSoaviDCHm5fcDbMWck5kXRcZ44fi4BQBLG5FCNFfG2O1R8hpgmo0emT5BzIqGREEzCkZnSBBtiN0U6STkDK5oXETd8dwfAQ8d5aS27fy0QMZMWcAAITAts73PGwk45bqZVf////7oOtbObF9RdK6zV6gAhNISAAABYyUUCwVEHfiwYRmam//uSxAoAlj2PT726AAsiqudp3SY5prZCxJhEahbE6Zmr+yOG37IKOAqEyb1GqKM3NEFpEWKx9TnSAkFGVDIopULOgZqiBojgFgQ9Ik0ITDNIoMYkBKqJii5stkPsit1sZXQUdICTpiiiQ4WUQYyKQm4CwcBQqMqTRFiLE2RUqnmMjAvbpqSaizKWtNHSTNbKLxgTySJiaq6ReS9L//9aLNWiitT6KKKNSReSSeoyRFdBcUwAYAADMwYAEQg8Y1UYcOg8YBC+aZHeHV0HAyOgS27HS+kDxBPGGpWtZ9lHlyyGUjwaSptuQ4rAWDSdd7TYeW06LzNXaTLWsO1PooqHF5hAXO1XQANbU4i8BROtWcXkGQrFuNTGQyLGA5y+/1fUixldJXqUty7Ib81PalON7HOkj8YdsyhlRgCiYVEZjYIYFhLQiaxXbOyQkMERpe8WlMqh5M1U7B4l+f9YnZQlpaetCpSIyqk962Lwm0r0DPcHm6fffD0XXGysvloAAAiswcBYxAGIwdso1lBcRjoZoY4ZbgdwwGAFLh/C+rQZczaCnP/7ksQTABf5Vzp13AATcqaovzmwAADABirpNOpuuVgvF5Z+CI1TtZnLD1yGXurdtQzDsw81jrKDKJZ1jOpGpqaxp5RWo72tVO0dJu1yrzW8uXfsZ7zx5hnzmeVrLHnZIu6R3N4VauFbK7NY2L9qxTWs+dsdy/f5473nre8f5r6Bf9P3v/B1LCqVltp/p2ZcmGX2mpLk8U/BMrrwRGo3IZZG6r3GkpjlkGNWqJQzIkQAAACAQAKIcQIBAMAyCAAhFFjE9WBj+MDOoCOQyQRjbAUZyckBie50QFMTTiQ5MelYNAhEA3O9AesO9stU7LmwamuWsRUfa9DrlOUg0tRCgHAax2J0vx1LWkztS/qYCpGWFxy5bSmdONBMOfX1Ys2010qDBAwODDUiIZAQqBOKDQo2JfPMqwcLSyn79/+sXSITEbSH3/i6MqmT/rtzlrdv///n/uWc+nlc/dp9P7Y7jKY9DMFON3/oWz////uPJIpx9L3P//aUmEomqZy7JVf//VnQ1WJf////WMU99QABQCAAAABYnMYdJxneFG6iiFgYaj3/+5LECwCXnSU9vc2ACwwjJ5ncvTmJ0pDiQlO9fQHvYxwKjGJKXdcpJTOIiPzBbzxyG5PtrkTjcckOUYpb8YxpZXqll9ShkUepJbbuUkvlFfWrVJL6mVW1O0vxF8GdI3GDkhsM8bCYEpIb+rGTiRhIAgs5zuzvJnK7+dyfyt6wyqZXNfy1W7f+7vG7z7GO7GOVzG7vX37n9r65frfnVeBJPcRdy///9/seOuOAAAQAB4eHh4YAAAAIHh/T9AIAsiDeBDCMGgE1hgGEpihFJiOGJgYDpwfNpjyQBwJm6S3dpQjFbYYAC5r5DIY0FYGSR5uw9AtfMsOIhNqbtQwBoN3MGBSCVl5KKPrwrro0XBmPpxcjaguKCpDS1VetaUDjRQTbelAKINgPSsVnUyMs+W5pnKK8fPWyr5r1CbaYbYeZIdmyHaBJFlxNXOtNjnOpItlJFka4UOLJDVEBcAxHtlDFO9dGkaMz8/vfnR7MSbt2omAh5QOzfqOyOiP/////9gAA4wPAAkAUZJUy+C0Kg4YdFmaJgcYAkGcbRia5Cmgw/b9Q//uSxBGDl4VTOk68dcMCKybN5k8hEXOgZaQFA5pq0QwDXlXyx2IFzh4HnRTlGgBlIDyPGUT1+wn+eKJDZcVKF7JCFawyFvithOYmyPqmFHMmEJkepuCoNvVZEjNiOqrMsLx6nYEJikxPfWZPGjUtem4VaRosCG44brUfUkfvYy8opn28Od54X05P+z83wbPbsx7b/bDCsMPA0pHw4G1E6jYkU5C7CynkhtK0BMrNgCsskFAAwKImDhADACAeMHAcwxGQGDAWBSCqrRggg+mCiAYYAABqmzXZS9svGAAaWJQTGGxqW00MCwC0teNasuVtfiVxB1p9TGBInFIGnFbofE8PVSIEjsagZKT0lNioPoiclYHofnBKXwJ1LYlPwPxXMaQvd62kLtq1y7ttze5dfP71vY93s8ytlM+iYk6iXUEi6XTEmTyzhsOkHuTJgiaSX1aS1LektTs6K1H0UkVGZ5qaURvqkllySzysxWmUnQAAkwCABASAKYSh5JgNhdmEYGgY87iBgMiiBxIhxaqGmziQAYewJpghgvGBAA+CQEjAEP/7ksQZgtN5HSBPJpcSnSLjVd/wiQBCABnJMBsBRkksnJyrDcMKHCQjy832h+nyp9PjM37HrJ0CQKsHG5bVkK7ClMz2UZOtuTb5jBUfNhheqSkli9XVf77xnNrYO5d1Vc9+fDPBtfyHPWty4MmAImAzzQNUiCwIkRLnv0X/pIYYBIYYhcZ5Xuc7kKZcFmfIiWYooCUGB6gpJjxyk2YqoBhHNlWZrIxhIFg4ROaJApOQx4CX1cqMvFcgOJmBSCZ7CAqA2mQq1urAcMxun1T0konadwpydovoMaCthSTtDjX3cmLOU1rsvpOcl1NnIcd25RlnTWsZ/8OY2cc99y3l+97pub73/1hjh/5aynh0ARTmt9xx6+P91nSTbiDQSNTDuwMgFFYEAAAAgABBYEAOA8MAUAwwJANDEhAOMEgJswNi6zEmBrMJ0SQx3lajHmDdMJsEgwKgETATAGLQrGexTYaAaQ+cugkfwzLB0A8mBCj8Jzy7lqaz4Him2JXBA42ayMwMmcnvN0lJyN0z0AHJqMwp2XeOJfX79/qSG4aP7TBT9aL/+5LEPoIRCRslrw53Aiqi44njTuAZ+BOYnIckVA1S+sAAPEgFR0CAwJhjjFnAPMEcAUxnidQETuYTwPxqyqqGXuFkYLgHRQCahPceLQ4o6RAQt5EaSKTUhdAkAvCwBEDtRo6a9/Y9nrCTomEgogZxFrYBIHka/bSZmJoxcczCkvv3ObF7Hr7Uqet+a1aSn/f1KSIMNl/uZtqrGXDGgG+xZKQdL/1f0J9v+1Yu8YBAAxhLkvGISAsYDINxhIFRGSCEEYC4kJlTTDmMCAaYnQPZgngTIimAWAIglL5KdFACz+2G4v7PSFuRKBSNAqv2rmDpUTB5pNYdEA+iMDSIQpPRxEXehOxLA2ZRLdE1zmIllmEZChZJWF5bK2sWfkqTQIrcrizXxpdd3qr785JUbx9dHZvMi+ToIQAG2Ci2ivDNmztCCTLhBwFMvtoeUYyVDhuoNYlYFI871Nj1AxHgmJCEDA4va0xeSdTeU27stjT/SsLAsDC2XQDJrxpFESRk07SzDgFe5hxIc6X79dBRLZdjSMo/1W6aiRR6iM0SqspqJM2t//uSxHuCEtUZEg8mlUJTo2IVwy6psu3Oe3vtreov4HktbDp543S1j1gLg2TjAHSb1OA4N/ApoICtUTYPn1Um6k4+wlP3uzbIHboZEEgMAAOIAOMNQyEQrmMwKmGINCAgjXOBjTIgRoDwwKU1oQ06zNyyzqmprtinYaFBglEW1ya7DkGorS5I4VialBYaOhm8kVi2ta1+vJNjWmiaJHNNcwLXsdNf/rVszTTT0Sm62vWtK119Wy2iukulXSvLidyWZYUk+n2a1/zXOv8waa3XFoW64xnVvi3+Lbzr5exeSxEGllhLqlRESIggaLiY6zGLMFa09L8O7AUPwl+n9dp0W7NifeHJHIZdGZVM0NJfx/tLKo7HRBMYtEkCigI9Beb3Zna82aktrjUUjTij0FqSInFlmXm+aNLa43Kk4q41SREUJAzE1VPqXa9I3VxymQl6g2LIlDiKhNGkqH7mriqPQpGkcC2avVz61y9PdXHKZCbWPxBJWIlpp//yJUiUQNWJ/EJiDkoTQOf/KUxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqv/7ksSsAxPVfQJOofPChanXQYMy6aqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo="; + //切换金属 + public static final String switch_metal="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7f///+//8f8CAPr/FwAIAA0AEwD4/wEA8P////j/8v8PAAYADwACAAUABQD1//T//f/3/wwA9v8XAAsADAADAPf/AgDz//H/BAD0/xcA//8UAAMA/v8BAPb/8/////H/GAD9/xcACQAAAAYA9P/9//b/7P8NAPb/EwD+/wMAAgD3//3/+P/v/w0A+/8TAAAACwAPAPT//f/z//X/AwDw/wsA/f8NAAYA9v8EAPT/9v8BAPf/DwD//xIACwD9/wYA8f8AAPT/8f8HAPr/DAAEAAYABQD4/wUA9//2/wgAAAALAAMADAAOAPn/AwD3//3/AQD3/wkAAwAKAAsAAQAHAPv/AwD///7/CAABAAgACwAEAAQAAAAFAAAAAAACAAMACAAGAAEACAACAAUA+/8BAAEA//8FAAIACQAHAAQABgD9/wUA/f/8/wEAAQAHAAUAAwAHAP3/AgD7//3////8/woAAwAFAAYAAAABAPj////9//r/BQAFAAgAAQD9/wQA/P/6//n//f8IAP//AwABAAQAAwD7//3//f/+/wQAAAADAAEAAAACAAAA/f/6////BAD8/wIABQACAP//AQAAAP7///8AAAAAAQD//wEABQAAAPr///8FAAAA/P8AAAIAAAAAAAIAAAD+/wAAAgAAAExJU1R0AAAASU5GT0lOQU0WAAAATWV0YWxsaWMgTWVudSBQaW5nIDIAAElQUkQcAAAARmllbGQgUmVjb3JkaW5ncyBmb3IgR2FtZXMAAElBUlQOAAAARWwgRmluYWwgQm9zcwBJQ1JEBgAAADIwMjEAAElUUksCAAAAMgBpZDMgggAAAElEMwMAAAAAAHdUUEUxAAAADgAAAEVsIEZpbmFsIEJvc3NUSVQyAAAAFQAAAE1ldGFsbGljIE1lbnUgUGluZyAyVEFMQgAAABsAAABGaWVsZCBSZWNvcmRpbmdzIGZvciBHYW1lc1REUkMAAAAFAAAAMjAyMVRSQ0sAAAACAAAAMgA="; + //切换gta5 + public static final String switch_gta5= "//tQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAWAAAkuwARERERHBwcHBwnJycnMzMzMzM+Pj4+SUlJSUlVVVVVYGBgYGBsbGxsd3d3d3eCgoKCjo6Ojo6ZmZmZmaSkpKSwsLCwsLu7u7vHx8fHx9LS0tLd3d3d3enp6en09PT09P////8AAAAATGF2YzU4LjkxAAAAAAAAAAAAAAAAJAM2AAAAAAAAJLu9WbatAAAAAAAAAAAAAAAAAAAAAP/7kGQAD/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABExBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQAEAAEAAAAAIP/dAe/uel7/xf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABB+DMiTkUP+bi55qBsCGO9ADKolAxWS+XyfMAMkhUDJonC0rzQnFxjQAhqDheBhgDfPEoMgIAGYGKgGBksxgZnHoGOS+BkUT/mBotMpEVACF4GDx2BicZAZ4IAGUwCBiISfyfHeXF8DCwEA0iQwtOIQoiWBZR/zguxAMLTy4XyDmROA4AgLDgDRBsAwyRQNFk8DEQqAysJgMChkDCYF/+QQ6mT/8Dm87A4GiwDQUBhwCBicPkEFBZocuFrYs3//3ZN271IHnCysCQeAcIQMjh8DOorAwICg5MfANQKAMHwMQg8CgcAxQCAMnBAG8X////////+Bh4FAZKDAWDH7Uar4bDU+DsZjQZisWBbjtH5iAd53J2glGFAinQnwc3PZ6KZGCAiW9RPfM7tGjaxif5iDryg9mTN1f3vXbYsSsz8XNiMhQRXeqnci8/DE4jWFwcxsfAxWzwrCIFuQiG7cXzVSMMEgwQDgN4E6kf4i0bPPfc7GcgLIIDLKCipJlxmb/+5JkyAAAAAAABQAACAAADSCgAAEh4hDK+aqAAAAANIMAAACyVp/dfrDOntpqGEBRhAA0BvF8IDH3oVb5unh5/5ZGJyZp7d7WDsOJdU0a5IGIQ5ZnoOjNefoqKOxOxnnY1z//9MkiD8Q/f2gATEZJORProV5vKM0VBCX/ieGfcJfn3n/SczscXWgosI0wDC7/RRCQXgZIgP+WMvl1ud7qgkV6kq16aallmjAAMQABiNBpjAIJhEAb+Q007JuK9ndeWWXHvkjck/YdjVWGasomlNOTMdf6Xdodz8xAKtyFtL2CqOirJfutWxZYTOrSmCW8mpUm9DtruUv5UtkYLOFFeorK21Hu2sa1y3MJxVcs34fq1trFrcy1/n40tLulXjUncc7eXtc5jjjz6r0Tv9/eOOPe1rkf3VpKfP5mUf+TtS/nHwqQ9LNd3bl9v8Y7GMcda1k8cH6ytyCgypnf+gzpJ3VBYlMezqRq7cllqzRROzO6msJn6G+qAhCIAByPbAJlK0RJmLMKJbL8WJDBLax3FuZWG569OtYqQFaQD5ROnXZO//uSZP+ACDxmU+5zYAQAAA0gwAAAGZWbSp3cAAAAADSDgAAEUEAqWWqSOLXKA3N1s/gMKFbTPBGYaFKa6ExJjtphVjW4gv/s26Ac1/u0EL7UeEWzvdn/rsIBMKrcGz7Ww43WHqhK/UJEmPLOQJSuHRK1+LcY/yxx7XJ847y/np8Hh8It1jrxLjb6TXdNbP1VZnNhC1arC4JXTaThy921UxNmdE/VsX3O9CVprYFFJQ6T8dL6SJMf65VrMvRldBjZaFAmjSaVh4r4kwCAdCAONEDQAMMAlNUknJjTosdtRyCnWZ86TPS8FurKlb5blVWAtYcT31q7b1nHCwRv3zP7d2oKAkvtcp5V3RAHQIzRrW/+kDGdyqRpjaSTZbePj4p++HDb4OiHrwptQjI38B8IPL1wS83hT/LJj+CU/7W576JYnXTESJlJpz4XCbf9fHw46w3Wbew3+MFvmxh06YL8kwreAsIOVWlw5RGIR+YtWXqCqZHJ6sRIvhjaUomq4jQn1q1OigGBAyAAAAAAOvHhDiiL0sWQtMBQQstwQJT9eCWbRf/7kmTUA/aBZlGjmHvwAAANIAAAARc1m0qNvZsAAAA0gAAABOjaID6yy1F1Kr0rkgWDS6ko4buOZAFzq8hNFistFfXg/3zBMdb+FIrOt2n2IeNNV5OhJ3VlJkrWlAEjDThVbDrtozzX34ZP5spFkcsUBNSboZbPLOQ9AblOYk1Euqz7ccl8vvhCs/wFJTkgOLMmD9cZMjGdXYdeAkjvTeWtWtH5/MsVxPmNd6gCmpFbGS/N9HXzlQ2sdZ6Sqs5Y+MoeX9hXDesuKmwqIzAmC/tDbGRrQnVlagrTvMdXsamAgMgAB9OuGBwQl615AKy6y2R5Ys7bwO5Ebzdg4J37VG9eNLTMSn88H9hP2iV09SOuhlA1fBu0mr1l0sXwjAhCqCfxttfsS4gBFJntK9dueTtIz75BVzG9MoQbqTMXz26aGs/Q0DeSDkfc2e3XePu6qqpRz1AxrpdLE4DQYTcpATm4N0f4USZSxEPV+FRSb40JKqTkBTf0NQ8YT9+FQrKlbCGLPweHs5KDZ1szJaUup2fQz07eQjkSK6pUHzSyyVk3Ni3/+5JkzgP2ymZRc7h68AAADSAAAAEZqZ1IjmGRwAAANIAAAASiafRddS6hnydFegEnuAAcz9gQVQeZSyqHY08Cz46/U0xGXsHbuqbtmkXJjhnKLtrMlHC5yhWDimHjilPX+PRAmsF7sWs3SrdWixlOSN+66aTo3/TLfTlZnrSqXtPG8twW4P5cQESD3RVut8xRXkNmOQLJ8ZKMCov27S1iIUZ9fDKoJuTpK3qexueicVeerVfE8IfrlAajY/fo2mF0fq1uQyj6fImb86z9raFKhe4DMsKOZDENbWdfV8llwm51yqaOZ+HqpHcN/Hht6SVLW3vUefZ+OmJ+zu3j17BZGOIAmKQADk5IgcNz0vgxH68AMeqxBTtcfdyUiAm9YiSStq1aYbLJfUIQmlu9I8w3TRoE3W7+5ex21XIMtgqypei3KLK4vRxpSpWn3lmoaRMezTgOHa+hVF95VNyvzeACJk3yW9c+Jx6vzqSdrcYikHfZUV7hKl9xPDZAJ95zHbw39PC1nCs+jDLc3h5LGpAwIEilc/RlGJrcYmx9/Z/KW0iB//uSZLmD9plnUqN4fHAAAA0gAAABGp2ZSI7h9YgAADSAAAAE8puoyN+f0RaMJR2vWRL3OkoTsRTKn1LXC8prYQtNMaJQ9IruOhMDe4+Vu66JXO5arM9iJXMDdN0AHp1GYEAlO94cBX2UwRfX9SzLG0iIr5IMWfeWvDYkVPa0w6X/UKk+ecSdafmeLNyqzAWARg/JrrFfxa8VgZ8glQiT9JCSgLV1mbk0W3aVs515GMsQ9QaMep3FbftqXdc+S9RPycudW45J9WSbT6n4lvlqS19xIU+VUWy2TuUs3SJjsuJFLFbkQa2JG9UH3tdqhp6SHgj5p908U/j0zowTRi6kv8HtJAYzoQb2KiWBdQUOWWOrdNmy+oY7M0qhevBa3bmYhNlTK0QXNTq5hy4bBJjBAAVhzGRFQx84Yn6jh1JmHWxDwDU7L0wtypmIsScppS+MCxOeGTRtr2Sh0suzTW3n7VN8R6udStZrVyF49G1ZaTRySeVtWleqocUfr+6ItbY3BQmPWtyWm3BQXBe/kCyHTVZBIf9Kufzp0hr/9emRdvOBDP/7kmSkg/aYZ9KjmXtwAAANIAAAARu1n0SN4fWAAAA0gAAABGOlKyIlv9Z92tFcP6gJWifJ4Fo//N13Ic4+MtxnC+K/KRORm5sD+Q6LEBIOsJ8nJEmCwjuHlvLSZFsGPFTZeXhtXjne8tYn5eEi7XKmN49np0szm9S/ydhzHepkSiH8kQ7nzA/+VDZNAl9QADJFGAwKglTBBSEy9ur5ZUrVEH7N6Ppgzu2MIh2JnF3Hewf0RAtqFNtnstxsRy1ceEwQKW17uAlHV6N0ksDbwWpCdLtA1sMkWlyod6i+mMaEOkELqLiGXFAdrL/FwxsDR+HCyTqU3kH5Hqp3IToluumkNk0pzptYgRcbYamaNLMqGbPP6NKkRgrEiec0vptQmJ9m7E8jQ/6RJLhuP05Fr5HydMSEdSwnVTC2pWNwZ5SXxR6Y6ajcEqG6xeWTFaSx1rzVHjoOUra0+kyKz6AIBAOK5xr0RTfYwQPVgpW/bWTSNjSsVBK3gh+5g9SP0N2mZoMY/o0OJPI5xH2tzFuCBDypBJChT+bNdSQj+1HTuvcvpcf/+5JkiwP2hmfQw49mYAAADSAAAAEXuZ85Db2RyAAANIAAAARQkSaKztckFZZkydMSiJQ35gtjvBgiGqna4OpQ2X0bjb6CSbemJ0aQlDtXXUxvCwO2wOkl25ypnSUDVRpy7vRiTvFaM9nHjHsGoKmT1qPlrh9uEo++zJj0zh0vUp64XT1aJIkszk23l4kk3z0xd5l1l3miUTt7XWmFAhwAABCwyXLsNLZY77iMrbk6Dhvw77TY1hTQS1qBqWVdlVHdsKqoBUiXlkUTlLFjKl8dwKY11CSIeSqZa6sxRpXrWoVa9pDOVU1xGgwN6axJTaZcq1MHE9xFLqGqR8zEcyqfK59M1qGFZrNF1Btk5S2qm3N1G02kjiP1CWVuZi7CxR9f2YXFtNF1v4azRUL6GcrAdU+5BvAVikAUA1P5UspL+hooAFCVBOACMRUJU3QTgAkEBaCwA5QAAGIaJEAPlNCxUSMmgGswUCgZGRQtR5T6xo3VZhJ9ZVYzZq0jOpHGartRNnM5fYY8bxfVpbENO9PVGHS9jLqQfDLsyGmppuXHRa2h//uSZIKA9cZgyEMPPXAAAA0gAAABFal/A00xewAAADSAAAAE8VSzZMWiSWZwyuVnI0xOaPoTkJUa2tUwlKsKym0zm5/ac8cqdaMiVFrBl6Z7jopGyKNyOKzO5M7ap0lTuPVn6lYlj0TnjtWv/+HBkA0PJYx9fwPQEQIp3/pzZZdf2wDogQAYQDDd8qOHhUHSwxCPjDITe8xcSTDAoASKMKgQElGaQaaQCGNNwWWscsW7Fr//9/zuAwKaiZpUn1WLCNYVif2tvX//8xQZDs7OqfymQ5HZymX8xQwI5H6p//s5QwI7P///ymBHZ2MqOis5TKhzt9UBDn//8qS2CYapzAAAzItdENcRWYDgt74483OaCNE/AXDCUALE44OM8Jpg424Ewwp03gOoWv80ACEy/EYyGE82laNgizNboxzAOnLzgiUysgCwGqsFAkgFBYbAokYuMiUwbaTGqIZpbQZhBmGzhitKaKri/6cCmAArMECgcFkwIXqQSyuK0z///+n9f///////kUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVf/7kmSOiPPNVjcbmRJyAAANIAAAAREMYJLP92TAAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVWAAAG1zAgaYkYJjMtSGJqweZaSeBmxnZmYkWIY5JlZhFItGFAh0ZZZHZlbBLnP3cYWLZgERGAgmIwAwt729kVKX+iluVSlDO3/+v//7f6lM5UwyiU/qxpkf/8uZHRy////6/mOJ/yob5f//SX+4VVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkeA/zcmoYq9wSoAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ=="; + //返回gta5 + public static final String return_gta5= "//tQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAnAABAfAAJCRAQEBYWHR0dIyMqKiowMDc3Nz09PURESkpKUFBXV1ddXWRkZGpqanFxd3d3fn6EhISLi5GRkZiYnp6epaWlq6uysrK4uL+/v8XFzMzM0tLS2dnf39/m5uzs7PPz+fn5//8AAAAATGF2YzU4LjkxAAAAAAAAAAAAAAAAJAXPAAAAAAAAQHwCXws1AAAAAAAAAAAAAAAAAAAAAP/7kGQAD/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABExBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV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qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqAQGGAF/lYwrMkVU5ZA9VM062jOUnMJuwwO1DFKjMVHAwuUwsTDABfMTrYxQ8zA8UMG1wzbETSyaNAjcyggRJQDCHaJmuBqJhzyJ0Cpv5BjLpmpB0wZ2m5nZxjihnQQgAiQEusvtpDR1HlHmRuQ/dTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZHgP83UYk8Nc0VAAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kGRBD/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVMQU1FMy4xMDBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkQI/wAABpAAAACAAADSAAAAEAAAGkAAAAIAAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZECP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7kmRAj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU="; + //点击 + public static final String click= "SUQzBAAAAAAJbFRTU0UAAAAPAAADTGF2ZjU4LjQ1LjEwMABUSVQyAAAAEgAAA3d3dy52b2ljeS5uZXR3b3JrVEFMQgAAABIAAAN3d3cudm9pY3kubmV0d29ya1RQRTIAAAASAAADd3d3LnZvaWN5Lm5ldHdvcmtUUEUxAAAAEgAAA3d3dy52b2ljeS5uZXR3b3JrVENPUAAAABIAAAN3d3cudm9pY3kubmV0d29ya1REUkMAAAAFAAADMjAyNFRDT00AAAASAAADd3d3LnZvaWN5Lm5ldHdvcmtUQ09OAAAAEgAAA3d3dy52b2ljeS5uZXR3b3JrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/7VAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEluZm8AAAAPAAAAIAAAMMAACwsLExMTGxsbIyMjKysrMzMzOzs7QkJCSkpKSlJSUlpaWmJiYmpqanJycnp6eoGBgYmJiYmRkZGZmZmhoaGpqamxsbG5ubnAwMDIyMjI0NDQ2NjY4ODg6Ojo8PDw+Pj4////AAAAAExhdmM1OC45MQAAAAAAAAAAAAAAACQFEAAAAAAAADDAOzWXdP/7lEQAAAJLGVE1MMAAQmMavKYMAAuwm1MZhgABehPsIzDAAABAAEwNy2hBIAIAAAQRHTAw5s7P198u73/vcRERERF3d3d2TCAggQQOef8TggCAIHBICBz1g+DgIAgCHo+GKf/g+H/E58o75cPgAAACABArEs/gJAIAQBoTKnB5za9evvLuZwvdERERER3d3d3cAAAAQGPE7/BwEFAhBA5+kEAQBD/yn/8uD7/3fg+8ADhRTWgCRxxebITsiVEYxrD2sNX6XqTgLWK6L6uuzKbJbZBI/k0xD8jHC5kuqWHAn91YuyFlPCPOrn7xb0H7aatLIYlvX/5mZmZnEpo+d/hUYFXf4TCBW//qGFXagAFNGJSAJHfE7sBOypURjFuPKw1fpepOBTRxk0YfZFNgBlcgkfyaYh+Rh4MkpdPWKDnLqxd8LLcJV15+8W8xNbTVpY3Ez17fMzMzMtJfiPnf4VGHnf4TOCG//qGFXamAAEAACEKASNfVKkWq6jDF7SwXKv/7lEQKBAKjFNJfYSAMTkJqneykAAq4eUOsPGkhd5BqdYSJ1HS4s0iDKX1sNqqiaDbskQ1CflR1nLstskiygdAQEyphYsE2kg0depZP5YDhRyQyAl3jWV8VtY980tul5lQmESn0AAAAAAFCTdpDcWkluRbVtETFJQ4Jgsth2PCAWIujOMlVFRMBbsRgrUH1Lpxz2kWYeCo1jsxoF4BMB3/0ovnmv/+lOoX++KMqe8g6vbytoAoBZScCdNNGgYA1hX4m9IoIH8kyXkNAPrtbEP6iz2SNAuuo+QIkKbmbkY7McqBymrQxsPkSDxYmhCQiEFJKi9QTMyypxkVRRUZFsleJlgwkXo4sMT4AMAQSS025ghMSm0tAc9jih1psg+liTEoygKt0NM06A7pI+Fp9lHGGozT3Pd5nqRWsyTiWnwQDMOAoSc06QYFAVbApoKgIUcCh0B4aukGnt1Z5TreiyPNoh3Eh73NV4ADBYPNd42dutdJ9JZmlVpgoAmpAF59kwf/7lEQMgAKxN9FlYGAIWsYqv6egAQq0gzy5h4ABXgro1zTwAMbFHERgNQxjaQUCRgJTcqiQvFV9zOfDL/L0OFRqlDtX6dMy9aRwzc5Fh5C1euX4JSQ+JKyUizqfNelLXqXQAAIAkKWWyS3l7BtykDD6QEQ4AtAJREPEUPTXDtrQXsW64HlFRATC4+7oZojWdNpO9KsXXv02jdSTPyndT/HH/cXfxqMCqbwnPPLj4otV9NdDHfCqcWoNvvbcAKvvuA2UGVdI0IgcH7FOEyRnyTBUkjgypWYuK1RXSi5jQybxUObrNG4UrzVt3lky1Vz8Rb5190xne6x/imK0+vMGD5wIDlqCp3RB98jYoihsUW//1JAA/p/4SlC5lSo2gJgRGKJWA8VBrJJgsIE6BCAHQBhgKixd5VE8oIZcY/uxRbQrRJq79c7gZzTwB5EBLAwRSIAUIGFliBY+bhwY2xQHY0jo2zZiu3SxOqpAswI0KqzXOAQfOgWSaSLEiSRhiAqgMP/7lEQLgALJIlQGaYAAVoRaQM0wAAskW09dowAhXAlop7RgBbnGtQOxFdhbOCAHw8pXMpQuG46j+90Vxxaszet3KUONrLWfk5Y80wUTRcZTZ4KPWhQIAQGrL9zDmIor8c6h3/3mSCT5lEIVPmMgAwyPmDGkHLAJBIQWOpisjdFFaLqlXQU1gcDsOLMT1KJFZNH+0yvHmCBn+9yjjF67B3zbLLOMHJo0ZTj1k1JGGQSPKBVWgcjU/+zMf/SgdAgACTaikFRYElOHkYmSEhYmXhUdSEZSiZGr7PqeVOvbEBRyS8xZpyWlGnd431uMdSmKeLHQ0QDhlwu4MB1Jl4Pjhrnh54MHzhgaeVo3HWcALMUFgz45WoevAAAKZriSJukqA9DcMGlUmyVpIgBKComSq2rdL4k5/ggVVa0DjUkkhHMlGEx9JSTWTdV4sGRFdPA63k52XCPl7+tXIzy1S36K+T+0o9vmfP0r///v//9tgDSbrTkjabDtIKvERLfZxmtNQf/7lEQJgAKfHljrCRpMU8UqOmmDKwsYZz5t4MUBW5VmybMN0HzkBtG2DQkHhpkmDZTXrW2y4koKZw7BkFCVda5VMl/Y4JAyQZaEiLgCBhBB00cWPpXPHq97SjZUlqQmPoVsYvrbgBHJTbacDtIoiMcC0ZVBAo0bhiCsQNz87Lg+KjLcP46wEQuDqQnTbok9qjqCgULtr+dyM9zKyea3sjRRyXkk44Rh5ZFAobMdB4k/c8JRlrGBXlToKSKcHCoDGAp54LUYWGj1a7IBED5NAAgEKqFCGafVhsNFgVloxLIQkyPI+av+M9yyC5aiIqYBowgYcAYsEguADJBb14tcG1OnZZQpJmyAhqfZROGd9Uq2eWJC8aHQQKoJ0bICh8ahGHlugUVI0FzFLo4hjPO6+rtcENCxhl0Il4EEWrRjA9WflqADH6MLLFZQ0KyHVpJHJg2G6FkkrpSYWTfSw6HzbiomU+xxhjvqgFUACAAGWFDguYqSZ74xHminnhiwMxi8NP/7lGQLigNWIc1DmkjSP2KqXWEmYQ3owTAuYSUA8JSnWZYI4CkxUxZlTggCAESkfEHWcUhVQVMMEpkwIJbUWakntxtJSW7Jq5rq14TUjU/fpRe0oVQSrJlFix/gPWY1xcEHli1qXR/f9E+j+a4///JN4jd//+f/6wDS1zViZRgDYWDqGhsHha+5KyVwSNw7CdiTspFI8oGVBV0jibTy2jsXUxh2HiYu1sc6JUaWVe3/Six2/jSRlQlGgYFTCCgOVO8w6UDE54NWzjACrH2m4iZiHyhyc0XX7FliRTT1MgeQohfB8bdbyyFl1LQy07hE0nD0uvuz8blsGqPx7NW5bd++LXzVJ9Pxvzh2DJwsKtMUmh4gAOLNQ4w+FggkIkXoatyiYf07fXAwAUMjjYREselpcgKjM8eANyMDQslYlLjs9O3mXwRJUeKmFb6MWvZbyfWnqxjtQ2lPHKgVXWLGv///GJXANSuySyONwOUtxLYXbc5AauEECygP28EJe0rjR//7lEQOgAKDKdNrLBlYVuU6LWXjHQrAf0msJGjhRAyotYeM5BMoAoYQltSO8dg5jEoMXpgjjnnVjRbeb2RnLMoe69BhkGGkiwjY7IWJEQ2S0a67BzW9HbwCmrFWnFFIIGQcaUPn8CCZjmXY1Dz7aV0JRsqnhRJQQm7DCR1ZF8qZaddARCkDzLdmQ+Qq5/M11p3DQWKFAEMnaRrJsk4fNnTJ8SRimny6uODQS6C225gFOzspqNJwUq2kPzCxU6sTtu8v2BAwJhEUAWhQoTpMin8lO4cG8L0EHTcq/cGXq6tM9RYeNoLFRCsLFjAW2CgUSelXoZgVr1Gjd73GFtKg4/WNEkdmeBAnK040WnA1shMk+WBQKgcxJwkYml6M+GbeIwqazuoER0hCP2pUfCs073IiDmltY5Rd4+fnT4JhUVBBMYEAwOkUPol6j5Hdbc1Yuc6GkSbKFYzHgQTncEYDaGsSsR/Z8tyfkz1r/sn2A6NgIFF3VSlmELKmodG5KlB51f/7lEQVAAJhJU0DeDDCTCMKXTxDeQmMk0WHpGjhMYzqsPYY5veofdmU0Lu2l/WzG0vl+kXMO178bzuHlbXvvxb7rd+2t87wGrNm87HJIDTJ82ggUkWiZPE5lhIwn48ollScqAI4U12Y492OKC3d/JQOAw0CE6LsBePGOYJ0MIrFHK5R50cLKg6LixPrFTiPp/9b+ASVIlVMMEaISHwDFHW0nkjjsRhbohLpUjMqmyBQZYdyuPTU6+LJiySg/IVPuyJUhTlYnQOrAMARcmMcQc+y9oKblzttfs0Lq5kzbH0KKNyT/qoTpudCyTHeS05yBEHWLCLRsttLG3IKJjrkTTC42p9I9nysluVhjOSo0HXMIuBxDzZgFQg74JONIGip4ABgiL2o1i3q/l+bg1VGZmRZJXHAA/DDMIh4NxsIwmjAKU9UOFISXxURD6Ts8YELGTqk9Ss3Fjc6Z/FGo0kRmJe0Ube/+9U/hymtf6yz/7ui1+84XXo4VgwgABaIBbC8Zv/7lEQqgAJlG9j56RrOTCUZpmTDdAmoSz1MMGjBJgmnJZeYmFVCNkgKZ3HGKS19Z2AnJqwl9KI5ZyKUUEsSlkg1LaD6QEWzjuKBkVzmW/w+SArEcvwYdUi/QKYsOtscdt1PFPvZ9G+rAHEYE0XKH8srbB1kJftLYIvJoJKfJAYqGKnMpUVEoVainr8gPHoPAIKpQA4JhoQGCKS4ueSMPEB4l+6oYZcLxdEg50b9ToboQk0SMZjAUEAEbyGFMkEBxEhg6EkM8fSjRi3tIMcYMe6Kkqsnth0F8orH36eacWEJI08eSvAQXCR5xkHK1hwNJ9DoNgz0CWVJUyK7On9x1cAAABKTcgkjuDpQsARzZoiDGV2QK/OFh67/Jw0yaop587FWPIOucoYnB4Q2pZXXOE0U5qokzwNA8kcwR3vTco1wGcoIaG1rVLdNPrWK0BGKZNpspSBJEFLIQsrWI5TrO1YOFHk4WiWs4jGSSwEoAzNN1KueaRaZYsUOHFhh4leSLf/7lERAgAJpIU5TCRswTOL6LT0jVQmMqTDNJGzBLBprtPGKNhqjNE4ct1XWCrLMSPlxpVzNbCCPSLAA7WuIgAThBDtoSDoKTFCi1a+GpvtEWvxd6klsiYsZRtGTSJSR2KIXVJRuwcGVppXFuOxKv5WJmZBSn4598/IUShiclwD6iJ7JtabNor9tGSbttkkcbbYeD8sRRemRBKprMRFKtgLq2K9lXPapA0kCDPM0U+SDHTLPk2/mRyyNd9TJxDuVabKpqM3/XooIqBSEkYCFD1rT1zn96sBiAAIBUgUOqsOBf4iYKD1rP40hz3IjU0pvYf6vjdJgpyCtkTXqLpgjU0+0hQWBxLh6nBwmopi6KiwYdbx8Vnux6hdkNNOO1f4UAzsV4IDrpbaRajBkCzM4aAYJ+lsaFyNVErhmRUN7hCLxUhARwED5gAsbW2s4a17JOT/vbKid2Of3V3bZtPff2FhlxKLt6lOepCnCylfUp2sEAArBDqZRYWnHcG9p8YCgsv/7lERVgAJoGc1TJhugTQZ6HTxiiQlAXy7NYQNBLQ0mFYYZWPMQWPTLqtjTE7K3MsZwhgMkkmiQhvJLNdDFWj55XFj1ElwcEaBEp5IFWPCCQ+MVRsYpIonF/zaL6oCAc6EgR1RpLzppJxB0GVD4VlR4EB8NX3xHhMj/R/LtgQJIjYqkbvyhW05dPe3aSWnws6YFD54+DhoPCyhQDH17uTD+ELHj//Z+qmrAARtNJpqKMS2BW6j4H1d2AbkT5Ds7PpF/AJo5iDdrKMtdmWdMS5I9XSJq+dqPCrRVVgWbHn/6CgVWuZjyyqn5ZKaFTRUIb/Dv2K2YASAIr+NJXssKfAIloXbTIV0leoU0rOKQXMpjFki2OUW5sSQ3n3+zileYjbrc4bLO7O13BGgkIQiHFhMwo9ezRJDFhmhJ1s9pb//XgAUACJI66waehmmXQky8ouAvB/VNgMTkkQW7Op0kFpl1lZ7BnIFIRnL/E9bJOU0XuFSHNmPLPyY1GUUCJuQ2rv/7lGRrgAJbKFBrCBs4S4QJqWTCagmIpzcsMGehMZRm5YYNHMQ50qG83hn26u1PDuAJwCAkEvfpqiRgCOh0VSj6frfCa9CJlH1S9ZzTsGwEOylQ4U5BQoS55cM4yIXZdD1zj7EonL9SgKiAbC/e7CgiFawqXOuOJuYoDP6qgAAgAEtxiNsEIZGsIiYFQjBWmCAdlrlHtSvUOOTaNGyeFjUI5uIodbUlQ6V3CLOH+0u10NSn5Jf/lAjHGCdjXt1TqHqST2I6Jb/7a4AAQkAjDSPVQrnI7BUEQjDwDTA9pCA7kxInz2B1FiyIN4Z27XszSkYZTYSGbe1hFPIz9P5Vyz8PBuT2rLLOkRMERzQsOesdja///VjAFqi1g6kdYMYSIvJBLvddJ+dD7C+Emvmx0Wn2yaZGD2IVMS3EqA8iPTOisE3f5lenIfQYn+8zFMITJ9dK59winpgsCosifdQUJaQSAAEqQRlkQw+SUF7B7hHeJDgMUhVPQp82dKm0NLBlZP/7lESBgAJgKUxTBhugS2U53GGDHQlsoTUsMGkhL5GmXZSNmEa15ozrkcc2OEVp0r8n8uVPjc0tECYehy0v+tlpMzkJZy6gsuc0rf3WsIStwESQmVwZi1lMkSKZ5qCAuEg76CJVQBxRcWBJhWGSF0vYcTFA2KjMLBKHstTdLymYxSk3QLujmZJpnVh3m1evzNmzb+y/leZWUeHqbMHHZJI4442AXEXPRijdLeQk/zzdKaMuTGq6YpEybDubGD2Xqo/gJWg6Nqeuu/IRH0l2pMhKPRtodOFiA08Ey5IUG5MNhiUU2lrOaggShlZwTJmLkQgC4GGWFHBCeBU0cC8rBzQbnBPDJpXcvzRKdMvCpiWasQtIisARkNl2KDwEY5IhDIXNIsi7iERpdUaVH0EalUKwATDbSaabjBXAGYphhmAPwYTsSQwGZlgQyYICRht1wSdrTryiytLki6YjUDbiAgqMiENB1YiOGcSkGD0lU6SUqJBYUHFGbENMJUbR/+iJtf/7lESYAAJgP8zLDBFoSsUarT0FfYkwXzUnsMahNwnntPYY5CONf9XDOyinDfL0TZxYEiagCbdcg8lXDUafQDqOpdum1eRLTTxDwWTEDKjAQm52U36kZvKiWCiyDYPENPVgJyKxVi8TKiiCX7O3WCAQFwttOJET+IC6YXSUqJj1jOsv5sz6rhePNhlA2EVC8lWjRMm1TRtlbXGylFfuws67Zb6bNg8reG184uIoWgt2i+u5U8j8N+0AIAAKiHyFI865ISNM+UojD3DxlU0TjCAzLcoZw4WfayNpg+uhc9DYMoGpsuOS4Cpk5TQ6XafrV6xLT+GCQ+S99xWdbHNDodeukkgEbbbdX2oACsHucVkoE7gYMBLrUKnFthtPPIBpM2I45tu2FB0VJS3h3yAyZHDD4j6mCZnOH3HKeuVUknmZkf7pjQc86Z+RvxCYc74sAAAAgAA1g8LHzAgs4AmMZH2tgYLgxdpQGom5tlXnKzwdBmSyaHpmkrx0uWPUdZw6nP/7lGSvAEJlJFLh5hu8SWU5VmUjdgoooyrtJG6BFpTlSZYNmI4RRnMoXRbhD/dkQ/ZYFcmp3TaHBXn87/6y+eWMUcSFGMqZQ3sWARAGAlT/LLPeItQRljPNtFigNIxkybp+MCoEOaWDU31cEzE3qsuYDoKjoqLoch5Mc2TFRQJs58n9RqeUG3vSQAICwACW5QMX5GDGx4kAv2xpazvqEoAmcFgFqCVd1RQ42Ffp9MFJNoXWkks9qppl5lS8zpEX9VmXDtHjIyvye71o+C3X+5iL/1c9egpAm85m//7AydVFgvicBCBmJ4VIaJ0RjEhnKpUPXNTpVJ70ThQT8ZQzFSQ8zXD3+37P3E5xtqMPlm1CwE1/VtfUlqb3C7AVed11BAgtYOXMAlgpSMEEHBF44KQaaC2j8PuovE3TemDCz8SUTiQCSQl2aBeLkZjsZ5EwTzMI/lMuOjzU66OH05cGIxIUur5lRp8qtzk3kriOOPEgpuWgMgTRUUEsnIJf0tWsK//7lGTGgAK3M8pjbBtAPwIpZmXpJgmomy+sMGsJIRSpcJeMdiJoIkYBAPCYrYg3WFkDj2SPwWZnaRkVicJsETIDp9dGs9klDZCZezAd/1fnQldpjVfDnG7832Ks+7QCEABJNxSXzq+AEYL4ZOhNakka/C95tSBCFaoHNo/SQ6v2yKtL2Kuhlmf0YjQcGRW/xHTrYlSCC2z2LQcrRiTy0qtqIVnKlN/b/+z6AQAY3RCcOiB05GYYdmWhgyMvsBBpUCu2mu8mNADOoAbZOZNBI8jXFwciAgr3QD1R+iiKju6iJcbxCJ2VfP+Uc9wcw1UWAe8wkGkbY3/m+Ej3fvI966qYK/l0PNUJ3gjdBMgOFiyz48Q3GNwOpnEsBEQEpZcRGlXsIywZuRGhPKy16lLJ1U10CJpHGUc3efD6RmTdqF/azXqH/nC19+HuHWqAXUe9vv/ilWj5Kq5UfV6Y2jmmxwMoCZ1NEFhJKJDoeA1KmtuKYMKvfmwxjWEAuzE3aYjLGf/7lGTegAJtJ8ozKRuwTORpimGDSEmYpy1MMGsBU5CkVbYZ0fP5Uci2QGGklSqMrZ0lkitIZxZpNBPGcqOdDApNMsjVphRggnsWUjRGVtqGtf3fvq9b8osMALk004///tBYCFVTDiEhS1h0QSjEDi+xbse6qeWRlNSLpQNmZ/WIn1ccXnRk7e5zWb81ASaC8xihgOS6ObG7eDXflKmcPyolgna2abmzaNZVHd//1fZr+sElCQE+aAE7gCESHtM82WBTxMJTWGL68q56CY0okaQ9bHZafE06g8umSu3epa9y+19fWWasOOyGTIfaJg6Bg0QASlHA2MJiUXx/B0L7G/X///9v6wCAhf77RtTsdpJEya4umRADAq9W4clbF6eMPg5g8kmWLHQLAaK8gy+8UQLKeT9Ay0k0izkdZtXcrVZispldG6K5xRTH3R/e3ccocdBYACyUKU65z8m3vYob7rLvteaAACScfBeYMcGG4mNQoFBxlAMjGTDkSmYiEPUwfv/7lGTuAGK9NEmTKRtgZOZo0G0mpAoYpSTMMG0BTw1kXbwwYJtphgRbOmllxfqhGbZdMTatxfjQZIoFeMYQnjsbGc+fmZt8/P8hzI+bH4hKoThJx4isMz94lsDgFv8Zf9jP3a3/9YAXNAzBmInKkZqpikEFLShkObYnBj6o4Xobbit/OWSh3qsXiliJzE5cSvJliCiUTMaKQJNBHWxoEpxR1B5r6CiHhThB29jI/zPMzVfopQ2C0aXUe6//+z29VSHcS3Gjo9UNauchJi4Iql8gmMFIw2xMeOfBpErcmbf+VOwySObAoGw8FEuvnqNe+xh5uP7XdQ+Qb9rv5efx+XWrdF9efc/u9m0vCgIAUOX6sBBYFRrlLq01A5okDMyMqg5uAc6BkJcYJaZyULer6T/eAiACOrl0QIAAHmWxEHmsUEMbS5AdlaxPEYdHSad54iMyUmPBEIgkIhUXCxMCGmWRsxzzYyZ9LVt/2+jf/1AAEpyx+DwsjOE8NYRDA5fZNf/7lGTriOLyM8kzJhPQXuVZA2nmWgtA0SBMmHSBYROjhbyweALASJMtKAuIixsBgVFJAp6RpwoQDmexKW/YZnsjnlvKnVWeVKShbiB1oE4BA4KNl9nDQvmX7q92nf//oAQDBKNQVAo4MPEFTYRSWHZoOCWDrPbwkAYeJYjDkbBSasK2HlmRGOixmGmMJMYGj4IjpN91deu7VKqI3dQYOh+nA1zWBBNZmm3FDf9dtPpoqoIAFLoEq83AcvS8ORMCrFgJmrwuGs5dKzpGidSVmazBkNmAuKIGMW7kKMKIGUP3MdhjFRHZrSKVCMj6WbsLq5W7UIJobD4oStqIhsANAQnVu2f0iT7vSldKJgV2PbLzP1syw5OkkvqCVyjIFMNSUSNiF6p9yUf5RRM4diDWeRoFj4HD6IdYiw7CcJic+qWVYXeZXcWoRk1kw3jf/F7Ln1eX/tWG3vjzNihJ3KfIMucdXC0kz/qAIACtO01VhJvboKFjU4s2NUNf17twh2HBof/7lGThggKtH8eLKTNATSR5I2jCaAo4oyNNMEsBWJUlcZYNxE9JVNIZlL9P8+tlwZ0kFCXTZNAzJGqmuLTWks44oyUXMo8/9alJq9ornVjj3PllZ6Za6r3Pc28xKIHPXLDv0faer9i/9X0cBHEjCgcfUAYpya8IOBQguBiKtagbzp3GFBT6oDAUOkxDaWVsUjpg2sLPIxgVgJyT+PkOavSD5zZxm2o2mrt47PH9dI8QPWo6LPqjf++UbrsZEvYcKtgG40XBcR5KNoXiTjVvkrlCAUMNOdJfTbgUmoTw3IfF1W9AdoE8dq20V3IIHX/b3Gm55+7VVzCRV8BGzkBCQgKu9LzQSAocfKjP//66AGXiwEYoFnWQwEMjIiM4uBCUK4g6IIEWs18EttHhhEdL+MRFojXGYxCbYRPtgtcFIqJTFsE7ijCZ+ChYBmEGYYbYd9bSbg5q0ouVSbMEyKKsZrWvKeuiAVml0kpZSJYkqjVat3Sv+3106wA4COw6VQ4fSP/7lETqDqLyKEWDeWFgYCVI5msJLAosqRxNMMzJQw6jRZwwaMysM4CQMViSqbWAdXU6JQ5DNqYoKJuQgo4K5KXL3MTQNWQjjglUc6Vbk+b9P7b+uXyjAI5KUlRamdE7XLYtCC9XFmEkKA4BkHFUOCgycYYHbMs5zZoQApM4GMMH4gMRPXvoh+Ut67l7EiRlihNUhlCRNwRtILjTvWMAT3uhhReq89RKq///+6nTWrCkMlmAo6QOysqgHAxaCZcwVu4CJwAURIMjlaiPlQZLD8dBwKvKI6aeiiaNSJoOmbqRSxIub9Yz0+xdVLLxJxxAQIniAUKZZDlFlHOz6ACpDv9duojKFdEabMhRrVymq6iIt2uFwuxQKQKUWAcqJyV6EbTPtNW2w+hmMQO1ygZIg7S+9LNZz1sVDO9wrggMQQMXf/s1+kvMa7v39GgEJSkQFhMNeRQsGDQDBBSgvll6RcsTdDCOO6jwrln5TDVFQP/t2pY0qVTt4Uo0QSHHhze8QP/7lGTniONQKkULeUlwRsVI8mjDdglkeR7NJG0BPJGiwaYZmKcIHmmRpUKnMeDFtsoNLXqPd+1GJIrEymJhi5Aqu5jXAqqWmMDExc6MVVzDxIw0RfYADZMEFYWpioAKjj7lcM8XFmT55kyeGk0lntEpeaE8PtrlVtz/tDdXrQqY1gPZtnMT7LZrjacpyFTE92+ljFFFpYGLEilVtC9H2L+7/pHUwf6O0Fl6jIExT44AAyUg1yULrnEamswMANdcpzHYfdYBQwplQihME44FEwtgj1MR3WnDrVFBuuyeZRBQKKZHfbPJrTrCpIiCYGnRc+FzvQvez/uZq9j///u+OgCCAhVdtEqg8uFXC2gSBHwt+UgZ1CHTgF6AFFgHmSIQBqrGhD2B79MnrrSY1Gi3axuWdtt50wDwPGxyEhAOKUoSil/Zs+/R/6+/9HIABrGClK5LXlQiCBPAAyJKcD3NTnEVC0E6Mqh0fafMwr/kcaJWcSZ60H5pfBjMzwsvOSF6Gf/7lGTwCOJ4KMezSRNAVSU4oW8GLgxsqRItvM1BXQ6iiaYZ4C+jAtSswtoNwdDmlGPZ/r//1fpLpvcIQ88peMUNDSA4GqoIERYYGllDNUShj+MvDQrFwRQR9ACUOx3FI7h2eZpJD9EXWXy9HHVp7Rw4e9Eijj4Ft0EoM9dHMUaPLBUVqQbbJJwpvhqW0vTUoZtRov/y36QABpfyEsAHB4iOAggDB55wLbRmUDRmUi7IEBHF9Jaqaxu5F3E+BeT+Ky5VoByedEUnSj0zSs1zWSuPNNrL7nWvn4nIMBoaYgsAiRrxVy6+lPUF90YzNzsV+7SkIr9sjQBGJp6sIqaHPkJoIUY4DlzWaioq6riRF/l3xBWBMdjo/YIxWKbgNSkNKHIgOWsglUvzCrPYS9ycFNu+ZeIyI33XyTzxEFGjDSndSDUv4dmEF9xxzakq/bjKVIQAcjXcYICnSB4tIg0JMYQovFCikBNpfzdC/DXWVrUh7FxpWwx/7F+VxG5LNhZKDf/7lETuiAJjGcWzWEjAR+UpKmGDSgvwkQwNsG1Be5FiSbwYuGFEEDNuZhHaN5mTlRQFvfJfIz4cLgOdQBx8wp9DdgnRWi2nT+kurTlfv1IAdyWaCIXODHgA6IgQLIPHiqr+y+Mt5AERcJ1Fpl5ttKFYSojtypI9Opo8jp7SKK3xw/G/SWIEi6ShpAQDJ4MgouFxDHeLsirffrfrv02dzRNWxn+36nrGTVIWiTsyajHUCBSI0E2C2LluQrECsnQpYGak2T0wErjtUUkpst6iM6nhdhcDuhdGzJpj8GAxdggiNZkmBwacoUg+IVi9zvYxhxexnc7lr/+n/UoAAWZ+6ArKgPHWBkAtQ0odRXWvCEAKAXYrjgKmDFZhwcsmQxMyLPe7XmdYFAYTkCesCNiRQmAkmiQMAQ414X1xqTPmp+5sh/ma8mpqL6M8705C4AgABAAA1PQr4Ekw+mj0TSAqZVrAgJgqg6nn1VTeNxL6/SSRxQJK9P8Sts3swQKIzFibgv/7lGTzDOLZJESTbDMwWiRYgW8mLgrMZxAt5YNBTwyhwZYZ2CZkQnIYk9t1WlxHQ5mv+XmYZTfu5nWipaMheMrrZFUOVX9etea94XRX2FYJmERiCNcCJvwQ7HlpltXrrSaG3J7WlzbjVAuD4CjoDARyqJchU6SCDBR1PulWurikP9nCWtSn7T6siDQuOPiG44Q57Q3kb0+tLaf6K+aMRyvW2hi6ApXMACM3ioGVRaGFGxfg4qZWGElK+05oJQAChMxc2Dg5NjZ+NWfWqZPrGz986f7cvksGCLzAYxQGlyATESGveL9dHPbLulf/V/f/RZPwjqsILeg0sPGgqNHRMoQ2IQzMw00+1maZMt0jKuqNC9FgM0YFDEjpnbvNJRqzuakcjnNzDBEUAQOOLBNr0FRlQ5nSxpR2hK/S/QW0OinXs1jfqrigqC1EHXGDx8EYCeGeUqVrKpCtK4q7MUsHghl9XxQGkI1sqQvD8LPkyufWDKP1S04r40MA5sLWKHm4CP/7lGTxDoKdGcQTLBrQWMUYmWmDdAskhQwtYSOBMIuhxaww0INvPDCN3WM1eplV7PFkgGpcY+p2rem0v7hTzsmavIa+OZ1B6S/A0eWotzctzEKICeWaVNSpYHCSDKIZNTaRoIOICyhZpHu7RSdOljOdO09ODBUCFA6LkhqmTbE89oALMtYBoEIC80m40uMvfGO6Rb9O/IEoAzcm+MHKDgxcxRMHhkGAMMwoaFglEsJw/WLwSs9VpMdji4C4o/kSK3Nte0ofXxkXn5T1e7V9ixUTFZR4XoHN3+29H399P/qJbLpw1P57fToVWhack6h1kRIHUKTMo8qvKqKMbcIOiKLu4g+rSYhFV6MMmCFYKk22LJS7GFuRYp8JkyByxAyk6ay5uYMAjUgMNl7ZBKSC0h+0k2Et42LCgmUKNID6zTweLgQcRYC5p465rcEDT2iqbqt3n2HKgJ0rGqOwBAU16MtOyuQAjTmCbCRqnWTu6JtuWCo5bcvi4qwiKlDIeqn3Bv/7lGT2DMKtHMOLTzJQVCMIgmsJGgsccwwtYSNBRo9hybYZIPNJY9F+rl5l5S6/06fT/VRr1It697Yq/6E08qA7sDxjb3XMYQ/Zc+q3FN6rGWQMgTmJwEpfTIDRbWrm1zs1tvV5mmO25OpLkZy5ttrZrcYCQhBE8eGQJDYhnEi7qUCoLOFGhdg5ooIW0Iirj7RZSAqYi6N66bLkNVa2aYZjRDADMlaEXIPkSM4ndkAi2ohYJZRvm4MrcyPbaZkVrMh7sGqBvIwObKb3PbdVB2omA8Ddseq4JRmH43Vrqds9S39UsobcLHxRwyuWUX2Kosvk9yogFGqMcSOSEASGxDjXpMByOSEyahtRWzYcpnctgCoBDTgkDAgo0shFZRTxmX3Vj9jKE77bW+M+bsYu5KxgkBMXGnEy1z3Na9hbJ/NOhJCbJp0zuyvKWaWqZEIAWglWbdkdgdZmBi1SzrWmpNSLnlUAB2gxEiA4h5/ZuvOyxhQEn/aCQXiRXiq2WKFnZP/7lGT5jINFH0MTKTOgRCJogRspCgzweQYM4YUBR4yhmaeY6NYpSAOkiHgDePcArYGKnq23r4qipclY+x4xtliSxx6EWrF7yzBN2dFAGekaSoYOWsXESjIrNLguIMwjUTZzDlHRAMlmDypYbpTl8jnSQWmh/t601k1Xd5Qe0AqMpeC5MPrE7RXUu8tW4wWqxqKHLuMe5SCB4HV/2L62vo3LoCOw+5xwzQZHMaIISUgR2b6NxigL/zYoRoV0kYmQkCbJMqQ1EyTw1rmR/BkQc4M8OuFEiolHtyGJ23+Re6rSb31F+sxOPrexPeSoqqTS3fx1GBFZSw4U6etFtB6iGTQIDW8zC4NZXYc4bnUHEAQiUsdFcCWjs9fVr7urmIC1MQexomQ215EblFHTtyUWvytRuaip5QZ3mhzyFFzU30mXQtFr3dLzRAKzehwhSNfRsHyFBnlD8UTCtM45JoKId9Bc2NswOVXqLj4gA0nZNR5yjdaQxUIGSBB8m+/FZRei9v/7lGT0DILPIcILODDgVkMoZmGGSgscaQgtYSNBQo0hRaSNoCttCkn174obOUn4o6ZQF/K1nqnoljjMoAaAwo0yYFQNFFAShewdd0pWGlp8Vg7lsj4atQSrCt0CPZZmCwD1NqcGHGx9rm9vZwtMxhHE1+Op01yS/8VtlvT9r1ranqIfZ7OO013zO9+9Fz6eN/PoQqzN7X6MNnb6SACyWWli8DcBU8cHDAF/riZIviQ2FB6R8P3nNXmhwufTkZuLhaK3liISCo4MkqipygshTsTaxn/uuUjPQqMaP9NqTVRXMX+sbX2mIMzOs8R2/9uUf7czDfHVYo/3uJ3rv5X69tJMQU1FMy4xMDCqqqqqqqqqqsX3ec4gwNCApn5JWdSn6sm+A07kfGUo5YTxSyYHA3GcMQa5iWibA4QetALDyUjw0eC1SyCUmxzyo/eUHmxVKGmQ64AiyTCtNwkB8ywcka2qJvzwaHmRfhbhUPuk7Aw4P5ECCaZYRJgHrIgncjdGwf/7lGT1DMKjGkKTDDKQTaKoYmHmNgxcjwQNJG0Jkw0gyZYZmWPEIoPusTLxPdZC5enDyyTRluyj40FAofoLixSBywfWQWRhVqrWFaBSTOpU/1Pdvrv12R2+rnQ0LRgsqeasJ6Z6UwUljKBoYsGlxUKjTIiDUphV6FCgqxrSUSWzNqJVwlOgqdywNA1ip0qdEtYKhvf4NPDTJFT/JMcRgriJsO75BR6JWdsGsqdJMWGtYBBBcs1u11ukBOwEDoTc6RSs7PVuUVnq3Yd+WIz0l878Q7Pshr7/5XX/9X2VTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7lETljALVF8EDLxlgUiL4MGUjZgnUUPosJGVAsAGjtBEIBFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/7lGRRj/AAAGkAAAAIAAANIAAAAQAAAaQAAAAgAAA0gAAABFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVRBR3d3dy52b2ljeS5uZXR3b3JrAAAAAAAAAAAAAAAAAHd3dy52b2ljeS5uZXR3b3JrAAAAAAAAAAAAAAAAAHd3dy52b2ljeS5uZXR3b3JrAAAAAAAAAAAAAAAAADIwMjQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/"; + //点击2 + public static final String click2= "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qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//PgZAAAAAGkAOAAAAAAA0gBwAAATEFNRTMuMTAwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqTEFNRTMuMTAwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; + //点击3 + public static final String click3="UklGRo5ZAABXQVZFZm10IBIAAAABAAIARKwAABCxAgAEABAAAABkYXRhgEkAALcAtwCwAK8AqwCoAKUApQCeAJ4AlgCdAIwAlgCMAJYAkwCWAJMAkwCRAIwAjACMAIwAjACMAJEAkQCRAJEAjACMAIkAiQCHAIcAhACEAIQAfgB+AHQAdABsAG4AYQBmAFoAYABYAGAAVwBgAFcAYABXAFoATgBaAE4AWgBOAGAAWABhAGAAYQBhAGYAZQBmAGwAbgBwAHQAdAB0AHAAdABuAHQAZgB0AG4AeAB4AH4AeAB/AHkAfwB5AIQAfwCHAIQAiQCJAJEAjACTAJEAlgCWAJcAnQCeAKAApQCgAKUAngClAJ0AoACdAJ4AnQCdAJYAlgCRAJYAjACTAIwAkwCJAJMAhwCTAIcAkQCJAJEAiQCTAIwAlgCRAJYAkQCXAJMAnQCWAJ4AngClAKAAqACgAKgAoACrAKgAtQCwALcAtwC3ALcAtwC3ALsAtwC8ALsAvAC7ALwAuwC7ALwAvADEAMMAwwDDAMQAxQDIAMgAzwDIANIAzgDVANUA2gDVANUA1QDSANUAzwDSAMgAzgDEAMMAuwC7ALcAtwC1ALAAsACrAKgApQCdAJ4AnQCdAJ4AoACeAKAAngCgAJ4AngCeAJ4AnQCeAJYAlgCRAJEAjACMAIwAiQCMAIkAiQCEAH8AeQB4AHgAdAB4AHQAdAB0AHAAbgBsAGwAbABmAGwAbABsAGwAZgBsAGYAbgBsAHQAdAB5AHkAfwB/AH8AfwB/AH8AhACEAIQAfwCEAH8AfwB/AH4AfwB+AH8AeQB/AHkAfgB4AHkAdAB5AHQAeQB0AHkAdAB4AHAAeABwAHkAbgB4AGwAcABsAHQAcAB5AHgAfwB5AIQAfwCJAIwAkQCTAJ0AlwCgAJ4AqAClALAAqwC1AK8AtQCvALAAqwCvAKUAqACeAKAAnQCeAJ0AnQCXAJYAlgCTAJMAkwCXAJcAlwCdAKAAoAClAKUAqwCrALcAtwDDAMQAxADFAMUAxQDOAMgAzwDOANIAzgDSAM4A1QDOANoAzwDaANIA3ADVANoA0gDcANUA3ADaAN4A2gDcANoA3ADaAN4A3ADeAN4A3gDiANwA3gDVANwA0gDVAM8A0gDVANUA2gDaANoA1QDVANIAzwDPAM4AzgDOAMUAxADDALwAuwC3ALUArwCvAKUAqACeAKAAnQCeAJYAlwCRAJMAjACMAIkAjACJAIkAhACEAH4AfwB/AIQAhwCHAIkAiQCMAIkAiQCJAIcAiQCHAIQAhACEAH8AfwB/AIQAhACHAIQAhAB/AH8AfgB/AHkAeAB5AHQAeAB0AHQAcABwAG4AbgBuAGwAbgBuAGwAbgBuAHAAcABwAHAAbgBuAGwAbABmAGYAZQBlAGEAYQBgAGAAWABYAFIAUgBOAFIAUgBXAFcAVwBXAFcAUgBSAFIAUgBOAE0ATgBOAFIAUgBSAFIAUgBSAFIAVwBSAFgAVwBaAFoAYQBhAGUAYQBsAGUAbgBsAHAAdAB0AHQAdAB0AHQAeAB4AH4AeQB+AHkAfwB+AIQAhwCMAJEAkwCWAJcAlwCgAJ4AoACoAKUAqAClAKUAoACeAJ0AnQCTAJYAkQCTAIwAkQCJAIkAhwCJAIkAjACTAJcAoACoAK8AtQDEAM4A3gDkAP0AAgEbAR0BOAE7AUsBTAFgAWEBbgFyAXIBeAFuAXIBaAFrAWABYAFLAUsBOwE7AS8BMgElASUBHQEdARsBHQEaAR0BGgEdASMBKQEzATwBPAFCAUcBTAFZAVoBYQFkAWgBawFrAWsBawFrAWQBYQFgAWEBWgFZAVkBWQFUAVcBTwFUAVcBWQFMAUwBRwFLAVQBVAFZAVcBWgFXAVoBWgFrAWgBawFkAW4BcgGGAYcBkQGSAZ0BnwGpAawBvQHCAc4ByQHWAc8B2AHUAdQBzgHOAcUBuQG2AawBogGYAYsBfgFyAWQBYQFUAU8BRwFCAUEBPAE7ATgBOwE7AUIBQQFMAUcBRwE8AUcBQQFMAUcBTAFCAUcBOAE4ASkBKAEdARMBBgHzAOkA2gDVAMQAwwCoAKUAkwCRAIQAfwB4AHAAZgBgAGAAWABYAE4AVwBOAFgAWABgAGAAYABgAGEAZQBmAG4AdAB+AH8AfgB+AHkAfwB+AIkAiQCMAIcAhwB/AH8AeQB5AHgAeAB0AG4AZgBwAFoAWgBYADUAOgA1AE0AbABhAGAAYQBaAGwAhAB0ANUA3ADtAP0A0gCrAM8AzgD6AAIBEwH9ANIAxAC1AJcAVwBmAC8A//+n/kf+3f1V/Uj5R/jS9PnyIufZ46HlQuja55Xj7dS60sDPe8+M1Z3ZxufS6XzoJuio8Tv2pAJuBVkT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FgAvACkARwBIAG4AfgCTAJMAzwDSAPUABgEyATMBcgFuAZ0BnwHYAc8B1gHPAcQByQHOAcUBuQGpAXoBWgFPATIBDAECAeQAxQCoAJEAfwBuAEgAMwBYAD4APwAzAD8ARwBCAEcAiQCEALAAqwDeANwA+gABATIBLwFPAVQBkQGRAd0B1AHnAfQB4QHUAesB2AHtAesByQHCAakBkgFuAVkBJQETAfMA9QDiAM4AvACgAHgAZgBuAFIAbABlAHAAbgB/AIcAkQCJALsAuwDFAMUA5ADaAPYA+gDtAAEBGgEMASkBHQEjASUBJQEvATMBMgEoASkBLwFXAUcBSwFHAUcBKQEoAQwBFQEaAR0BHQEbARABCgHeANIA1QDVALsA0gC7ALwAtwC8AMQAxAC8ANUA3gDtAPYAAQEpAR0BKAEoAUcBKQFLAUwBWgFPAWsBawF6AYcBhgFyAXIBawFkAXgBiwGdAX8BeAFzAYYBcwF+AW4BaAFgAVcBTAFCATMBMwEaARoBJQEKARMBFQEQASkBLwEdAU8BRwFBAUcBYAFoAXIBegF6AX4BegGGAYYBmAGiAaIBrAGdAXIBeAGJAZEBawF6AVcBTwE7ATIBMwE8ASMBHQECAe0A/QDzAPMA/QDtAOkA9gDeAOkA7QDeAOQA2gDVAOQA8wDkAOIA+gDtAAwB/QAaAQoBCgEMASgBKAEyAS8BLwE4ASgBJQEoASMBHQEaAQEBEAEQAQwBGgEMAQwBEwECAfMA9QDrAP0A9QDtAOkAEwECAQYBEAECAf0A6wDkAPYA6QDVAOkA2gDPANUAtwCwALAAqACvALsArwC3ALsApQCwAKAAtQDOANIA9gD1APoAAQElASMBKQEvATsBPAFLATsBRwFCASkBOAEpARoBHQETAfYA7QC8AM8AtQC1ALcAqAB/AJEAeQCHAIwAjACTAJ0AngCwAMgAxQD2APMA+gACARoBKAFLAUIBTAFZAVoBVAFgAXMBcgF+AW4BawFMAVQBOwEpAQYBGwEGAQYB3gDVAM4AzwCrAKgAsACeALAAtQC1ALcAoACvAMUAyADcANwA9gDrAAoBDAEaASUBMgE7AU8BSwF+AX4BkQGRAYkBlgGpAakBqQGlAZYBmAGfAZYBkQF4AW4BZAFLAUcBSwFBAUsBPAE4ATMBOwEjAUsBOwFLATsBQgE4AVkBQgFXAUwBWQFHAWABYAFZAVQBWQE4AUEBOwFZAUwBTwFZAVoBSwFUATMBfgFhAX8BeAF/AW4BfwF/AYcBfgF+AXMBcgFaAUsBJQEVARMBGgH1APYA7QDcANUAzgDEAN4AzgDPANwA5ADeAP0A8wAGAfoACgEMARABAgEQAQYBAgH2APMA8wD9AOIA8wDiAN4A3gDpAOsA5ADcANIA3ADkAOIA3ADiANwA1QC7AK8AlgCWAJYAnQCRAJYAhwB/AHQAZgBmAGAAWABuAIkAeQCJAH4AjACTAIkAhwCeAKgAqAC7AKAAoACgAKsAtQC3AMUA0gDVAN4A2gDkAM4A6QDeAN4A0gDrANoA3gDiAPUA3ADiAMUAxQClALcAnQCXAIkAnQBlAGYAcABwAFgAWgBgAGYAYQB0AGwAcACTAJYAtwC7AM4AzgDkAPMAGgEdASgBOwEpASkBHQEoARUBJQEoATgBIwElAQwB9QDaANUAxADIAMMArwCWAJMAbABsAIcAjACJAJYApQCdAJcAoAC3ANIAyADOAOIA3gD1AOIA9QACAQYBHQEVARsBEAECAfoAAgEGAf0AAQEBAfMA9QDcAOkAzwDcAOsA4gDOANUArwC8AMMAvAC7AM8AsAC7AMMAsAC7AMMAqwCwALsAwwDOANIA2gDcANIA5ADzAOIA6QDzANwA6QD6APUA8wDiAOkA3gC8ALAAqwC3ALsAtwCTAH4AcABsAGYAhAB/AIwAbABYAHAAWgBlAFgAYQBlAIQAcACRAJYAfgCEAJYAqAC3AKgAvAC1AKAAtwDEALsA0gDVALsAuwDFAMQAuwC7AKUAqACvAJMAoACTAIQAfwBuAGYAWABYAFcAVwAzADUAOgA6AEIAQgAyAD8APwBSAGwAYAB5AIQAdAB+AJ0AlgC8AMUA2gDiAN4A6wDeAPMA5ADaAMgA0gDOANIAzgDOALAAqACeAKsAnQCvAJYAqACXAJcAkwCWAK8AlwCTAJMArwCoAMMAxQDaANoAwwDcANoA3gDtAPUA8wD6AAEBAQECAQIB8wD9ABABGwEVARsBFQE4ARMBLwEdASMBGgEpASUBMgEQAR0BEAEjAQIBAQHzAPoA3ADkANoA3ADDAM4ApQDEAMgA3gDPAOIAvADEALwA1QDDAM4AvADEAMMAxADPAN4A7QABAe0A4gDPANoA3AD1ANwA6wD1APMA+gD1AOIA9gDzAPUA7QDiAOsA6QDaAM8A2gDIANUAxQC7ALsAqwCvALUApQCWAJcAkQCTAJMAfwCHAIwAeACJAHAAbgB0AHgAeACHAH8AfgCHAIcAkQCJAJEAlgCwAKAAyADDANoA1QDkAOkA7QACAfYA3ADcAM8A3gDPAM4AwwCwAJ0AiQBhAFIAMwAvACkAEgAbAAoA/v8MAAoACgD//xkACgAfABIAMwAyAEcAQgBmAGwAfwB+AH8AfgCdAJEAlwCWAKsAlwCTAJ0AqACwALcAuwDDALwAuwCwAKsAtQDEAMMAxAC8AK8AqACoAJMAkQCTAJ4AoACJAJMAfgB+AIkAhwCMAJMAkwCJAIcAiQCJAH8AhwCRAJMAhwCTAIwAqACXAJcApQCWALAAuwCeAMgAxQDPANIA6QDzABsBCgETARUBFQElAS8BQgFLATgBLwEpAS8BJQEpARsBGgEKAfUAAQHpAO0A2gDaAMQAxAC8ALsA0gDFALwAvADFALwAvADEAK8AsADOAM4A1QDeAPUA9QDpAO0AAgETATMBOAFHAUwBQgFPAXoBhgGSAakBkgGWAYcBfwFzAWsBYAFgAU8BMwEzASUBBgEGAeQA2gDEALAAvAC3AIcAhAB/AIkAlwCWAJEAkwClALcAuwDIAOsA7QABAQwBGwEbATwBSwFUAVkBbgFyAXgBcwFzAX8BawF4AXIBaAFgAUcBKAEjAe0A0gDVAMQAzwC3AIcAhAB0AGAAeABlAEcANQAfAB8APgAvAFoASABOAFIAZgBXAHQAbgCMAJEAtwC1AM8AzgDrAO0A7QDiAAEB/QD1AN4A1QDcAN4A0gDrAM8AwwDDAKgAngCWAIcAfwBuAGYAZQBSAFoAVwBNAD8APgBaAFIAWABXAEcAVwBlAHAAjACHAJ0AlgCWAKAAqwClANUA3gDpAOsAyADSANUA3ADcAMgAxQDPALwAwwC7ALUAlwCWAJ0AkwClAIwAlwCHAHkAfwB5AHgAiQCeAJcAlwCRAIwAlgCJAJYAlwCXAK8AsAClAM4AwwDFAMQAxAC7AMgAvADiAM4A6wDzAOsA9gDcAOIA3gDtAOkA8wD1AO0A6QDVAOQA3ADcANwA0gDSAM8AyADPAMgA4gDVALsAyADVALwAwwDEALAArwCrAJ4ArwCoAK8AqwCTAJYApQCvALsAtwC8ALwA1QDpAPYA7QAQASMBLwElAUcBOwFLAUIBaAFzAVkBOwFCATIBLwEvAVQBOwE4ARMBFQECARMBAgEVAfYACgEGAfYA6wDtANwA3gDOAMUAvAC7ALcAwwCvAMMAsADFALwAtwCoAMUAsADOALwAzgDEAOkAyAD6AN4A5ADVANoAxQDIALcAxQC8ALcAtQCJAIwAkwCTAIcAiQB/AH4AfwBmAHgAbgCEAHgAeAB0AIQAfgCJAHkAfwB4AIkAhwB0AHgAhABwAJEAjABuAGwAeAB+AIQAiQCWAJEAnQCHAKUAlwCrALAApQCwAKgAqwCoAJ4ApQCdAIcAkQCJAHgAWgBaAE0AVwBaAE4AZQBlAFgAWABaAGEAZgB0AIkAfgC3AK8AoACgAKsArwC7ALwAxADSANwA0gDcAM8A2gDeAO0A8wAMAf0A9gD2APoA6QD6AOQA3ADrANIAzwDSAM8A3ADPAKgAqAClAJ0AxACdAKsAtwCrALAAvAC7ANIAxADpAN4A+gD1ABABAQETASUBJQEbATgBKQEzASkBKAEzATIBIwEbARsBJQEvASMBHQEdASMBKAETASMBEAEbAQwBHQECARsBEAH9AP0AGwH6AOsA8wDSAN4A3ADeAPMA8wAGAQIB6QDkAPUA4gACAfoA2gDaANoA1QDaANoA1QDPAM4AvADDAMUA1QDIALwAtQDIALwAxQC7AMQAxQDDAMQAvAC7ALsAtQCrAKgAkwCXAHgAiQBhAGYAUgBSAGAAWABlAFgATgA+AEcANQBlAGAAZgBaAGAATgBgAE4AbABhAG4AZgCJAGwAiQBuAHQAZgBwAHkAfwB/AIcAhACJAGYAYQBOAFoAVwBgAFcAZQBsAHkAZgBhAFgAZQBSAHgAYQCJAHkAeABsAHQAZgBwAG4AcAB+AHkAfwCHAIQAlwCXAH4AfwB+AIwAjACJAIwAhwB/AH4AiQCTAIkAjAB/AH4AfgB4AHkAdAB0AH4AeQBwAJEAfgCWAJ0AngCrAKsArwDIAOIA1QDVANoA7QDeAOsA6QDzAOsA8wD2APoA1QDrANwA6wDkAO0A6QD2AN4A8wDcAN4AvADVAM4A0gDIANIA4gDeAM4A4gDFAM4A1QDeAMUAzwC7AN4A2gDeANwA6wDkAPoA9QD6AOsACgEBARoBAQEMARMBCgEbARsBCgEGAQEBFQH9AP0A6QABAdwA5ADPAMgAzwDeANUA1QDpAOsA/QD6AP0AAgHkAO0A9QABAQYB9QDzAAIB6QDcAPMA7QDVAM4AyADEALcAsACvAK8AqwCeAIcAdAB+AGwAhAB+AH8AZgCMAIkAjACJAHkAhABlAGUAeAB4AJYAhwB/AH4AfgBuAH4AhABwAHAAjACMAJYAhABmAHQAdABmAIkAYABmAG4AYQBXAFgAWABgAEgATgBOAEIATQBOAEgAVwA+AE0ARwBlAE4AbABsAG4AbABwAHAAfwCEAIkAkQCWAIwApQCdALAAtwDEALwA1QDDAM8AwwDPAMUAzwDFAM4AwwC1AKgAqwCgALAAkwCgAJcAiQCTAJMAhACRAJMAngCXAKUAoAC3AK8AyADeANUA0gDrANoA9gABARoBCgEKAQwBEAEBAQoBCgEQARABGwEMAQoBBgH6AO0A9QDeAOIA5ADSAM4AwwCwAK8AvADIAM8AtQCrAK8AsACwALsAuwC3AKgAsACwALUAwwDEAM8A3gDEAM4A9QDkANIAzwDFALsAzwDaAM4A3ADPANwA2gDcAN4A6wDiAN4A3ADaAOkA4gDkAOQA1QDFANUAxQDVAOkA7QDzAN4A2gDkAM8AuwC7ALsAyADiAN4A9QDkAM4AzwDpAOsA6wD6APUA6QD9APYA/QD1APMA7QD2APoAEAH1AAYBBgHaANwAyAC8AM8AwwDDAMUAxQC1AKAAlgCoAKAAngCdAKAAlwCoAKUAoAClAKsAkwC3ALsA0gDFAMQAyADiAM8A4gDkAMUA3gDpANUAyADPAM4AzgC3ALsAxAC3ANUAzgC1AKgAqwCoALUApQClAKUAlgCHAKAAjACdAJcAngCHAHQAdABuAH4AbgB0AHgAeAB0AHgAdAB/AH8AjAB/AHkAfwBwAGEAeQB0AGYAbgBOAFcATgBCAD8APwBOAGYAWgBgAFcAWgBYAJMAjACMAJcAlgCoAKgAqwDIANIAyADDAKgArwC1ALwAxADFAMUAxQC3ALUAnQCoAIcAkQCTAJ0AngCdAJcAngCEAIQAjACdAKgAtQC7ALsAuwDDALsAuwDEALwAyADaAN4A5ADcANIA2gDeAO0A6QD6AAIB5AD2AO0A8wD6AAIB9QAGAfMA6wDkAOQA9QDiANwA5ADtAOsA9gAMARMBGgEQASMBEwEKAQoBEAEbARoBEAEdARUBAgHiAPMA+gDtAAEB8wD6AAYB9gABAesA3gD6AP0A9gD6APoA9QDzAN4A9gAKAfMACgEaARABHQEQASMBGgEjARABHQEyASgBEwH6AP0ABgH9APMA6wDiANoAzwDVAM8AwwC8AKgArwCRAJcAkwCRAGwAcABlAH4AYQB0AG4AjACHAJYAlgCgAJMAnQCXAKgAoACeAJYAlgCRAJcApQCRAIwAeQBwAHgAeQBwAHQAcABsAGYAYABmAFcAVwBXAGwAUgBgAFoATgBOAFoATQBCAE0APwA6ACgAIQAyAC8AGQAbACYAGQAbABsAMgAvACgAKAApADMAMgAvADIARwBaAEIAbgBaAGYAYQBuAH8AeQB0AIQAjABsAHAAdAB4AG4AeQB5AHQAcAB4AHgAbgB+AHkAYQBaAGAAPwBaAFIAQgBXAE4AWABlAFoAUgBgAG4AfgCEAIwAnQCTALcAuwDOAMgA2gDSANIA4gDSAOQA8wDrAO0A6wDiAPUA7QDkAPUA7QDrAO0AAQECAQEB/QD9AAEBBgEQAQwBAQEBAfoA/QAGAfUA/QAKAQIBBgETAQwBBgH6APoAEAEVARoBHQEyATMBJQEoAS8BMgEbASgBMgEvASMBLwEoASkBFQEKARABEAECAe0A9gDzAN4A3gDSAMgA3ADeAMMAyADPAMMA0gDOALAAtwCvAKgAuwC1AJ0AngCMAJYAjACEAJMAjACHAJEAqwCrAJEAlgB/AHkAkwB/AIkAiQCHAIcAkQBwAHAAbABaAFgAbABgAGAAUgBgAEgAUgBNAE0AMwBNAE0ATQA1AEgAMgBCADoAPgBCADIAMwBCADoAPgA6AEcAPgBCADMATgBIAE4AVwBOAEgAWABOAGYAYABsAGAAZgBYAH8AZgBlAGYAWgBgAGYAWgBaAFoATgBNAE0AUgA/AE4ATQBCAEgASABaAGEAbgB0AIwAfwCEAH4AlgCWAKUAqwCvALUAqwCrAKUAnQCeAKUApQCgAJ0AlgCTAIwAeACEAH4AeQB0AIQAhwCJAJ4AlwCTAJcAiQCJAIwAjACRAJYAkQClAJYAngClAK8AngCoAJ4AsACvAKUAoACvALcAyACvAMMAtQC7AMgAxQC8ANIAxQDeANUA0gDSANwAzwDSAOIA2gDSAOsAyADeAO0A6wDaAPMA2gDiANoAzgDIAN4AwwDeAMMAzgDSANoAvAC7AKsAtwCwALAAwwDOAMMAxQDFAMQA1QDSANUA3ADcAN4A3ADPAMgA1QDFAMQAqACTALUAqACeAKUAqwCgALUAoAClAKAAkwCXAKUAqACwAK8ArwCrAKgAoACwAKsApQClAK8AsACrAJ4AnQCJAIcAhAB+AHQAhwCEAIwAeQB+AHkAfwBlAJYAfgCMAIkAlwCWAJcAfwCeAKUAnQCMAJ4AhAB4AG4AcABuAHkAYACJAHQAfgB0AHgAbgB4AGwAfwB+AHAAhAB+AGwAiQCJAIQAjAB0AGwAfwB4AGwAeABmAGwAiQBuAIQAfgB5AG4AdAB4AHQAfwCHAIkAjAB+AJYAjACWAJ4AlwCRAKUAqAC7AKsAuwC3AJMAjACWAJMArwC8AKsAsAC8ALcAuwC7ALwApQCwAKsApQClAJ4AngCXAKAAjACTAJ0AlwCWAJcAoACRALAAuwC1ALAAxQC8AM8AxADVANwA2gDVAN4A3ADrAPYA8wD6AO0A8wDcANUA3ADaANUA6wDkAOQA8wDtAOIA6QDcANIA3ADIALsAzgDSAMgA1QDPAMMAwwC7ALwAuwC3ALcAvADFAOIAzwDcAM8A4gDrAOIA3ADiAOsA6wD9AAIB7QABAfUABgEKAQoBGgEKAfYA6wD6ABMBFQElARoBIwECAQEBAQH9AAEBEAHtAPUA8wDkAPMA/QDrAPMA4gDzAP0A9gD6APoA8wDzAO0A9gAKAf0A9QDzAAIB8wDpAOsA+gDrAO0A3gDkANUA6QDeAM8A1QDVAMQA3ADFAMMAvADIALwAuwCrALsAtQCgAKsAqACWAKgAngCHAJEAlgCdAKgAlgCrAJcAlwCHAIwAkQCrALUAsAClAKUAnQCoALAAtwC3ALcArwC3AK8AoACeAKAAkwBwAGYAfwBlAFoAVwBSAFcATQBHAE4ATQAzADIAMwAyAD8AMwBCAEgASABOAGwAhAB5AHAAcABwAH4AeQCJAJYAlwCgALAAvADEAMUAuwDEALwAuwDEAMgAuwDDALAAuwC1ALAAsACoAKAArwCoALcAoAC3ALsAvACrAKgArwDFALsA2gDIAN4A0gDkAO0A8wDkAPMA8wABARoBGwEKARABAQElAR0BHQEjASgBKQEyASMBLwEdAS8BIwEzASUBKQEKARUBGwEdARMBLwEaARMBCgECARABEAEMARAB+gABARABEAEGAQwBEwEVARUBGgEaAQoBEAETARMBIwEbARsBEAEaASMBGwETARoBKAEjAQoBCgEBAfoA6QDtAOsA4gDPAMgAyADFALsAvADOALwAyADEAM8A1QDPAM8A3gDSAOIA3ADVANUAyAC7AM8A1QC8ALUAtwC1AKgAkwCvAKAApQCeAKAAkwCdAIQAkwCJAIwAiQCHAHAAeQB/AHkAeACRAIQAiQCHAH4AeQBwAGYAfgB/AH4AfwCEAIwAbgBsAH8AfwCHAIQAfgBuAHAAeQBuAHgAbABsAHAAeQB0AHQAeABsAHkAiQB/AHAAkwCdAKgAlwCrAJcAlgClAJ4AqwCrAKgAlgCXAIcAfwCWAJ0AlgClAJ0AngC1ALUAvADIAMgA2gC7AMgAzgDVANIA1QDaANIA2gDIAOkA5ADzAOIA3gDcANIAyADpAN4A5ADeAOQA5AD2AOsA8wDkAPMA9QAGAQEBDAEGARABCgECAQoBEAEVASMBHQEjASMBKQEVARsBGwEQARMBGgEdASkBLwEpAR0BFQEGAQwB9gACAfUA4gDiANUAxADSAM4A4gDcANUA2gDEAM4AxQDaAO0A8wDzAPYA9gACAf0A9gAGAQoBFQEKAQwBHQEQARsBEAEQARoBJQEVARsBBgEBAdoA0gDDALAArwDPAAIBDAEyATwBLwEjAdIAtQCWAIkAdABsAGYAWgBOAFcAeQBwAH4AfgCHAHkAbgBIAFcAYQB+AH8AqACXAKAAngCeAKgAsACoAKUApQCeAKAAqAC1AMUAwwCrAKsApQCMAG4AbABXAGEATgBIAEgAPgBSAE4ARwBXAE4ARwBmAGEAYQBsAGEAYQBhAGAAcABgAG4AbACHAIcAkwB+AJEAjACXAJ0AqwClAMQAqwCrAK8AoACJAJMAiQB5AH8AfgBuAG4AbgCHAIwAlgCRAH8AfwCWAIcAkwCXAIwAlgCoAJMAtQC1ALwAvADcAMgA5ADcAOkA6QDeAOsA6wDtAPoA8wDpANoAzwDPAMgA1QDiAOIAzwDPAM8AzwDpAOIA1QDiAOQA5ADrAAYB5AD6APUA9gDzAPoACgEGAfoAEwEMAQwBGwEaARUBIwEVARoBLwElAR0BKAETARsBCgEaAQIB9gDtAPoA9gDrAPMAAgHkAAIB1QDIANIA4gDPANoA3ADVAPUADAH2APUA3AD1AOsA9QDpAPUA9QABAekA+gDtAPUA6QD1APUADAH1APYA5ADrANUA9gDkAAEB3ADeAPUA7QDkAPUA9QDzAPMA7QDeANUA0gDiAN4A5ADeAOkAzwDVANoA6wDcANoA8wDpAM8A0gDcAOIA8wDpANUA3ADFAM4AvAC7AKsAtwCvAJ4AtQCgAKUAuwCwALwArwCgAKsAnQCdAK8AqwCeAKAAoAC1AMMAqwCdAJMAeAB4AIkAhwCMAIwAkwB/AJEAeQB0AIkAhwClAJ4AkwCdAHQAeACHAHkAkwCTAJEAnQCRAHkAfgBuAE4AUgBYAE4AUgBaAGYAZgBSAEgAMwAvAD8ARwBOAFoAeQB5AGUAZQBgAGEAVwBlAH4AdACTAHgAhwB5AIQAZgB+AG4AfwB0AIkAhwB+AGYAiQCHAHAAeQB5AHgAfgB+AH4AdAB+AIkAeQB0AIkAlgB/AH8AiQCJAJYAlgCMAJ0AngCoAMMAwwDaAOIA4gDpANwA1QDzAO0AAQECAQYBAgEGAQIBHQEVARABEAEpATIBKQEzAR0BHQEvASgBMwFLAUIBQgEjASkBQQEpAS8BLwEKARUBAgEGARMBFQEMAQIB+gD9AAEB9gAMAQoB/QAMAQwBHQEyASkBJQEdASMBHQElASUBGgEoASkBGgEMARsBCgEbARoBAQEMAQEBAgH2ABUBHQETARABEwEVARsBCgEBAQEBFQECAQIB9QACAfoA5ADaAOQA4gDaAOQA1QDPAM8AwwDPANUAuwCwAKsAsAC8AMMAvAC8ALsArwCwAJ4AnQCdAKgAkwCTAHkAfwBuAG4AZQBlAGEAeQB0AJYAhwBuAGUAYQBhAGEAZgBlAGYAYABXAFIAVwBgAFoAUgBIAFcATQBgAE4ATQBSAEgANQBaAE4AbABlAFgAUgBaAE0AUgBXAEcATgBhAE0AWABOAGAAWgBHAFIAbgBsAIQAcABgAHQAZQBgAHgAfgB/AIcAeACEAIcAhAB+AHgAhACJAH8AeQB+AH8AjACJAH4AhwCEAIwAfgCTAJMAjACXAJYAoAC1AKgAtQC1AK8ArwCvAMQAzgC3ALwAxAC3AMgAyAC8ANIAzwDaANoA3gDiAOkA4gDkAOQA6wDSAOQA2gDiANUA1QDaANUA2gDFAMMAwwC7ANIAxQDiAMMAzgDiAOsA5ADzAAoBJQEjASkBGgEoARUBGgEbATsBRwFBAUwBQQE4ATsBMwEzAS8BRwEzATwBHQEvASMBJQEKARAB6QABAfMADAH6AAIB9gD1AN4A3ADtAP0AAQH2APUAAQH6APMA9QDrAPMA+gDtAPMA8wD6AAIB+gD9AAIB9gD2AOIA2gDcANoAzwDEAK8AtQCMAJEAbgB4AG4AbAB0AG4AeQCMAHQAeAB4AHgAeACEAH8AhwCJAIwAjACdAHAAeABwAGwAdAB5AGwAVwBYAFcAZQBhAG4AZgBOAEIAOgA+ADoAUgBYAEgARwBNAE0AWgBXAG4AZgBuAHAAZgBwAHQAZQBwAG4AbgBwAHAAfwB0AHkAdAB5AGwAdABgAGAAZgBwAG4AYQBmAFcAYQBaAGwAfgCHAIkAhwCRAJYAjACWAIkAhwCXAKgAqAClALsAsADDANIAuwDIANIAzgDrAOkA6QDkANwA3gDpAOQAAQEBAd4A6QDVAN4AzgDVANoA2gDVANIA4gDrANwAzwDPANIAzgDcANIA0gDVANUA4gDeAO0A5ADaAOIA9QDrAOkA5ADkAOkA8wD2APUA6QAGAQwBAQEGAQoBCgEGARoBCgEaAQwBHQEKARABCgEMAQEB9QAGAQYBAgEMAQIBDAH6AAYBAQH6AOsA7QD6APUAEAEVAfYA9gDtAOkA3ADtAP0AAQHpAN4AxQDeAMMAuwDDAMgA1QDkANUA5ADaAOQA1QDcAMUA3ADPANoA1QDpAOIA6QDSAM8AwwDSANoA3ADIAMUAuwC3ALAAoACrALsArwC8AJYAlwCgAJ4AqwCWAJMAlwB5AH8AiQB+AJEAkQCdAIkAngB/AIQAcAB/AGYAZgBmAGwAZgBsAGAAWABIAFIASABsAGUAhAB0AIwAfgBlAGYAYABSAGEAWgBhAE4AWgBOAFoASAA/ACkATgBHAGwAbACTAHkAfwB/AJcAfwClAIcApQCdALcAngCoAKsAkwCWAK8AnQDEAKsAtwCoAJ4AiQCMAHAAngCTAK8AqACoAJEAiQB+AH4AeACMAIwAjACeAKgAtQCrAJ0AzgC7AMUAuwC8AMgAxQDOANIA3gDSAM8AvADEAM8AyADSANwA5ADVALwAzgC7AMgAtQC7ALUAqwClAJMAlgCXAJMApQCMAIwAnQCgALsAxAC1AMMAoACrAKsAqAC7AMQAzgDSAM4AzgC7ALwAwwC8AMUAxQDaAPMA0gDaAM8A4gDiAOkA5ADtAOQA4gDVAMgAxQDVAMgAzwDaAOkA8wDrAN4A3gDPAOIA5ADkAPMA6QDzAPMA9gDzAOkA6QD9AOQA3gDzAAIB6wDeANoAzgDPAPUA5ADcAO0A4gDtAOIAzgDcAOQA0gDeAMgAzwDDALsAxADDAMgAyADFALsAxQDEANIAzgDIANoA3gDaANoA1QDDAMMAxQDFANwA3gDcANUAxQDDANwAxAC8AMQAvADIANUAvADVAM4AtwC8ALAAtQDaALAAvAC8AKUAsACrAKUAuwCeAJ4AlgB+AGwAiQB+AHQAdABXAE4AWgBSAFIAZQBuAHQAZgBhAG4AbgBgAHQAeQCHAIwAdAB0AH4AZgBuAIQAcACHAGYAfwB+AHAAhACHAIQAbgCEAHgAeACEAIwAkQCWAIkAhACTAJEAqwCXAJMAiQCTAJMAngCRAIwAlwCoAKgAqwCgALUAtQC7AMgAuwDEANIA1QDcAOkA3ADtAPUA9QAMAQYBEAEMAe0A4gDkANwA3ADeANwA2gAKAf0AAgH9AO0A8wD9AOkA9QD1AOQA6wDiAPUAAgECARUBGwEBAQoB9gD6ABUBIwElARUBFQEbARMBDAEaARUBGwEbARsBCgEMAQwBBgECAQoBBgEdARABAgEGAQwBEwEQASMBFQElAQoBEAEdAQYB/QACAQYBEAEaARoBIwEbARsBEAEGAQoBEAEBAfUA+gDkAOkAzgDaAN4A6QDeAPUA1QDeAM4AxADSAM4AwwDDAM4AxADEALwAxQDOAMMAxAC1ALcAqACvAJ4ApQCoAJ0ApQCgAJYApQCMAH8AfgCRAIkAiQB/AH4AeQBwAIQAfwBmAGUAbgCEAIcAiQCTAJYAhAB5AHQAVwBsAG4AbgB4AGYAWgCEAHgAZQBIAFoAWgBgAFIAVwBXAGEASABwAGYAbgBhAGUAYQBhAE0AZQBlAGYAYQBSAG4AZQBXAH4AcABuAG4AkQCEAJYAngCWAJEAiQB0AH8AeACeAJ4AkQCRAIwAhwCTAKAApQClAK8AqwClAKUAlgClAH4AkQCRAIkAkQCHAKgAngClAKgAlgCdAJYAqAClALsArwC3ANUAzwDEAMUAxADSANwA6wDpAO0A6QDrAPUAAgEQAQIBAQEMAQEBAgEVARMBIwEdAQoBGwEKARAB/QAKAQYBCgEBARMBCgETASgBGwEQARoB/QAGAfUA/QDzAPMA6QD1APMA6wDiAOsA5ADpAO0A8wDcAPMA5ADkAN4A3ADpAOkA1QDeAMQAyADSANIA0gDpAOkA7QDVANIA2gDVAMgAyAC7AMUAxQDOALwAxQC3ALsAtQCvALwAtQCeAK8AtQC7ALAAvACdALUAqAClAJYAlwCHAIQAiQCRAJ4AngCvALAApQCwAJ0AoACeAJcAlgCEAHQAeQB5AHAAeQB0AGEAVwBOAEIAbABwAHkAfgBwAHgAbgBmAGYAeABhAGAAVwBXAGYAZQB+AIwAeQCJAJ4AnQCWAJYAkQB4AIwAdABwAHQAfgCEAG4AYQB4AHAAkQCHAIcAkQCRAJEAoACdAKgArwClAJMAqwCdAJ4AngCHAG4AhAB0AH8AbgBsAGUAfwB0AH4AeACRAJMAiQCXAJYApQCWAIcAhwCRAKgAsADOALsA0gDPANUA0gDIAMMA4gDPAN4A2gDrANUA3gDeANIA3ADrAN4A9QDtAOIA3gDPANIA7QDeAO0A8wD2APMA8wDzABUBBgH9AP0ABgETASUBIwEjASgBDAEQAQYBDAEVARoBKQElARMBEAEVASMBFQETAQwBEwECAQoBAQECAekA/QDkAPMA6wDeANoA5ADiAOkA3gDrAAIB+gD9AAYB5AD6APUA6QDpAOkA2gDPAOIA0gDPANUAzwDOAMgAuwDaAMUAxADEAMgAvAC7ALwA2gDFANIAvACwAKgAnQCXAKUAlwCgAJMAlgCHAIcAfgCHAIcAeQB+AIQAeQBmAG4AbgBhAH4AZQB4AHkAbgBaAGUAZgB5AHAAfwB+AH8AhACTAHkAfwB/AHQAdAB+AHgAhwB/AK8AkQB5AIcAkQB+AHgAdABsAGEAYABaAG4AYABlAFgAYABOAGEAWABmAGwAeABhAHAAbABuAGYAdABwAHQAYQBsAGEAbgBaAHAAeAB4AHgAdAB5AHQAdACHAHQAjAB/AJYAeACMAH8AkQCEAH8AbgCMAH4AkwB0AJ0AkQClAJcAqACTALUAkwCTAH4AfwCEAJ4AeQCdAJMAngCeALUAngDEALcArwCdALAAtQCrAJ4AxAC7AK8ApQCwAKUAuwC7AMgAyADcAMgA1QDcAPMA7QD2AN4A7QDtAPYA+gD1AAEB9QAGARMBCgETAQwBHQEaARsBKQEdAS8BGgElARUBEwETARAB9QAGAf0AAQEKARsB/QAKAfUA/QAMARABCgEMARMBFQEVARUBGgEzARABJQEdASMBPAEpAUEBLwEpASkBKAEvATwBOwEzASkBHQETARUBFQECAQIB+gD6AOsA5AD2APUA5ADtAPMA8wDpANwA3ADtAPMA8wD1AO0ABgH1AN4A7QD6APYA6wDtAO0A7QDaANIA2gDPANoA3gDVANUAvADDALwAwwCrAMUAuwC3AJMAkwB/AH4AbgBuAHAAYQBmAGwAZQBmAG4AdAB+AGwAfgBuAGAAWgB/AHQAhAB4AJEAkQCHAHQAhAB5AIQAkQB4AIQAfwB4AJMAlgB/AH8AkwCEAJEAkwCHAIwAiQB/AJEAfwB5AHQAcABmAHkAZgB5AGwAYABuAHkAYAB4AH4AngB5AH8AbgB5AGYAjAB/AIQAiQCMAIkArwCTALUAoACrALAAtQCoALsAtQCwAK8AuwCwALUAsAC3ALsAzwDDAOQA0gDiAOIA2gDeAPYA6QAGAQEB7QD1APUA9gD6APoAAQEGARAB+gAGAQEBJQEpAQwBIwEoASkBMwEoASgBOAElATMBLwFBAUsBWQFZAU8BQgFaAXgBYQFXAVoBTwFZAWABWgFaAX4BWQFuATsBOwFHAUcBKQFCASgBKAEvASkBGwEvAR0BGwEQARUBKQEdAQwBIwH6ABABFQETAQYBEwEQAQoBCgETASMBJQEMASUBJQEdARsBFQEMARsBBgEKAQwBAgECARMB6QACAeIA2gDcAM8AxQDVANoA4gDeAM4AwwDPALcAxAC8AM4A0gDFALsAwwDDALwAwwDDAMMAxQC7AK8AyACrAKsApQClAK8AqACdAKsAqACJAIQAhACRAHQAbACRAH4AfwBwAHgAbgBwAHQAbgBgAHQAYABXAFoAZQBYAE4AQgBIAE0AWABsAGAAWgB0AGUAcABhAGUAZQBlAGYAbABmAGwAdABwAGwAZQBmAG4AZgB0AG4AbABmAHAAcAB0AHQAZQBuAHgAdAB/AIwAngCWAJEAkwCgAJ4AkwCTAKUAlgCdAKgAsACvALAAsAClALUAtwC7ALAAuwCoALAAwwDDALwAvACwAKgAvAC7ALcAzwDVAN4AxQDSAN4A6wDrAPMA3gDVANIA2gDzAOsA4gD9AOIA9QD9AAEB6QDzAPUA4gDtAPUA7QDpAOIA7QDtAOkA9gDpAOQA5ADeAN4A4gDrAOQA9gDrAPoA8wDzAPUA+gDtAP0A5ADzAOQA2gDVAOkA5ADiAOkAzwDiANUA4gDiAMQA2gDpAOIA4gDiANIAzwDcAMUA5ADcAN4A3gDFAM4AxQDIAMUA0gDOAMUA1QDVALwAyAC7AM8AzwDDAMUAzgC1ALwAtwC7AMMAwwC1ALsAqwCwALAAtQDDAMQApQC1AK8AtQClAJ0ApQCvAJMApQCgAJ4AuwC7AK8AsAClALsAtwCvAKsAuwC7ALsAtQCrAKgAtQCXAJ0AjAClAJ4AkwCTAJ0AfgCXAIkAeACWAIkAeQCEAIcAhACEAJEAlgCMAIkAjACEAJ4AlgCdAJcApQCMAJMAlwCWAJcAuwCWAIkAoACXAKAAqwCdAJEAkwCWAJMAkwB+AHgAhwCJAJEAiQCJAIkAhAB0AHQAeACTAJcAhACRAIcAlgCgAKUAtwCrALwAsAC3ALsAtQCXAJ4ArwCvALsA0gDeAMMAxQDIAMMAxADDAMMAyAC8AMQAvADEAMQAvACvAJ4ArwCoAKUAlwC1ALwAngCWAJ4AqAC7ALsAsADEALUAuwC1ANIA0gDcAM4A1QDtAOkA4gDeANwA4gDkAOIA0gDaALsAyADFANIA6QDEAMMA0gC7ALsAsAC7AK8ArwClAKAArwC3AK8AtQCvALcAqwC3ALUAtQCoALcAsAC7AKgAsACvALcAtwDPALUAuwCwALUAoACvAIwAqACXAKsAnQCgAKAAngB+AIQAlgCgAIcAkwCEAIwAfwCRAJMAlwB5AIQAfgCHAIwAkQB4AJ0AlwCTAIwAkwCRAJcAfgBwAHgAhwCJAIwAiQCMAH8AjACHAIkAhwCMAIQAhwBwAHkAeAB5AH4AbAB0AGUAhABwAH4AeABhAGwAeQBsAG4AZgBYAGAAbABNAGUAYABsAGUAVwBHAGYAWgBsAFgAWABYAFoAMwBgAGAAYQBaAGEAWgBmAGYAhAB4AIQAkQCWAHgAhACEAIQAdACJAH8AlwB/AKgAlgCRAIwAlgCJAHkAeAB+AHQAdAB4AH4AfgCHAHkAeQB4AJcAhACJAIkAfgB0AJEAhwCvAKgAtwC3AM4AoADEALAAtQC3AMQAyADcAMgA3ADOAM8A1QDIALwA0gC3AMUAwwC1ALwAxQDDALwAvAC8ALsAtQDDANIA1QDIAOIA5ADpAAEB9QAQAQoBAgEMAQoBDAEdARsBJQElASMBEwEMAf0AAQECAQoBDAETAQIBKAEaAQoBFQH6APYAFQETARsBCgH9AP0A/QD6AAwB9gABAf0A3ADaAPUA7QDkAPoA6QDtAOsA5AACAfMA4gD2AOkA6QDzAOIA3gDiAOQA3gDSAM8AzgDVALwA0gDFANIAxADVALsAuwCgAJcAqwCeAK8AvACvALUAvACwAK8AtwCJAKgAjACgAJ0AnQCWAIwAfgCHAHQAeQBuAGYAZQBhAFIATQBaAGAAYABaAEcAUgBXAE0AYABXAGYAbgBlAGAAeACHAJEAkwCEAIQAiQB5AIQAdABaAFIAYABYAGEAWgBgAFIATQA/AFIARwBSAEgAWgBaAGwAZQB0AGAAYABOAGEAWABaAGEAbgBhAHQAcAB5AHkAdABwAHAAbgB4AGAAeQB/AIwAiQCMAJcApQCeAK8AqAC1ALAAuwC8AMQA0gDDAMgAyAC3AM4AuwDVAM4A1QDeAO0AyADkAPMA/QAQAR0BGgEjAR0BJQFCAUwBRwFUAUcBTAFPAS8BOwEpATMBOAElARABEAH2AP0AAgEKASgBMwEbATgBQQFCAUEBQgE8AUwBKQE4ASkBPAEvATMBIwEzATsBMgE4ATIBIwEpAR0BIwEjAR0BFQETAQIBAQH9AP0A5ADrANoA2gDeAOIA3ADiAO0A5ADEAM8A5ADpAOIA9gDiAPoA8wDrAPUABgHtAPoA9gDzAPoA9gAGAfYA6wDVAOsA0gDzAOIA1QDIALUAoACgAKsArwCrAKUAqwCJAIwAlgCTAJEAiQC3AKsAqwCeAKgAqwCvAJ0AtwCoAJMAnQCWAJYAlwCTAKAAlwCgAJEAlwCMAJEAhACWAJYAjAB/AJMAhwB4AG4AYQBXAFoARwBlAFgAYQBsAGEAZQBmAFoAZQBaAGwAYQCHAHAAjACEAJMAfwB4AGYAYQBYAFgATgBSAEgAWAA+AFIATgBCAFcATgBNAFoATgBlAGAAYQBuAG4AcAB+AGUAdAB+AHkAeQCWAIkAjACTAJEAkwB/AGwAbgBsAHgAfwB4AHQAhwB/AF9QTVjeDgAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNC4yLjItYzA2MyA1My4zNTE3MzUsIDIwMDgvMDcvMjItMTg6MTE6MTIgICAgICAgICI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczp4bXBETT0iaHR0cDovL25zLmFkb2JlLmNvbS94bXAvMS4wL0R5bmFtaWNNZWRpYS8iCiAgICB4bWxuczp3YXY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veG1wL3dhdi8xLjAvIgogICB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFNvdW5kYm9vdGggQ1M0IChYTVBEb2NPcHNUZW1wb3JhbDoyMDA4LjA3LjE4KSIKICAgeG1wOkNyZWF0ZURhdGU9IjIwMDktMTEtMjJUMTE6Mjg6MzgrMDI6MDAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMDktMTEtMjJUMTE6MzA6NDUrMDI6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDA5LTExLTIyVDExOjMwOjQ1KzAyOjAwIgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjUzRUZFQ0I1NDlEN0RFMTE5RDIzQUZDRTBDM0IzREE5IgogICB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjY5REY5QkI1NDlEN0RFMTE5RDIzQUZDRTBDM0IzREE5IgogICB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6NjlERjlCQjU0OUQ3REUxMTlEMjNBRkNFMEMzQjNEQTkiCiAgIHdhdjpOYXRpdmVEaWdlc3Q9IkRJU1AsSUFSVCxJQ01ULElDT1AsSUNSRCxJRU5HLElHTlIsSU5BTSxJU0ZUOzhBNjNBNkNFOTMzMzY1NUMzMTE2RDE3Q0Y4NUY3NDEyIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NjlERjlCQjU0OUQ3REUxMTlEMjNBRkNFMEMzQjNEQTkiCiAgICAgIHN0RXZ0OndoZW49IjIwMDktMTEtMjJUMTE6MzA6NDUrMDI6MDAiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFNvdW5kYm9vdGggQ1M0IChYTVBEb2NPcHNUZW1wb3JhbDoyMDA4LjA3LjE4KSIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLzsvbWV0YWRhdGEiLz4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NTNFRkVDQjU0OUQ3REUxMTlEMjNBRkNFMEMzQjNEQTkiCiAgICAgIHN0RXZ0OndoZW49IjIwMDktMTEtMjJUMTE6MzA6NDUrMDI6MDAiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFNvdW5kYm9vdGggQ1M0IChYTVBEb2NPcHNUZW1wb3JhbDoyMDA4LjA3LjE4KSIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iL2NvbnRlbnQiLz4KICAgIDwvcmRmOlNlcT4KICAgPC94bXBNTTpIaXN0b3J5PgogICA8eG1wRE06VHJhY2tzPgogICAgPHJkZjpCYWc+CiAgICAgPHJkZjpsaQogICAgICB4bXBETTp0cmFja05hbWU9IkN1ZVBvaW50IE1hcmtlcnMiCiAgICAgIHhtcERNOnRyYWNrVHlwZT0iRkxWQ3VlUG9pbnQiCiAgICAgIHhtcERNOmZyYW1lUmF0ZT0iZjI1NDAxNjAwMDAwMCIvPgogICAgPC9yZGY6QmFnPgogICA8L3htcERNOlRyYWNrcz4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz5DcjhyVAAAAL7vyv4AAABUAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBZG9iZSBTb3VuZGJvb3RoIENTNCAoWE1QRG9jT3BzAERJU1AEAAAAAQAAAExJU1SSAAAASU5GT0lDUkQaAAAAMjAwOS0xMS0yMlQxMToyODozOCswMjowMABJQVJUAAAAAElOQU0AAAAASUdOUgAAAABJQ01UAAAAAElFTkcAAAAASUNPUAAAAABJU0ZUNAAAAEFkb2JlIFNvdW5kYm9vdGggQ1M0IChYTVBEb2NPcHNUZW1wb3JhbDoyMDA4LjA3LjE4KQA="; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiCallback.java b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiCallback.java new file mode 100644 index 0000000..f049d4d --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiCallback.java @@ -0,0 +1,78 @@ +package com.bytecat.algui.AlguiManager; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/10 14:37 + * @Describe 监听事件回调接口 + */ +import android.graphics.Canvas; +import android.os.Message; +import android.view.SurfaceHolder; +import java.util.HashMap; + +public class AlguiCallback { + + public static final String TAG = "AlguiCallback"; + + //普通点击事件监听器 + public interface Click { + public void click(boolean isChecked);//点击 + } + + //项事件监听器 + public interface Item { + public void item(int itemId);//切换项 + } + + //网络事件监听器 + public interface Web { + public void web(Message msg);//服务器返回结果 + } + + //网络请求回调接口 + public interface NetworkCallback { + void onSuccess(String response); + } + //输入事件监听器 + public static abstract class Input { + public abstract void start(String text);//开始 (开始输入) + public abstract void update(String text);//更新 (正在输入 内容被改变) + public abstract void end(String text)//结束 (结束输入) + public void buttonClick(String text) {}//按下按钮 {选择性实现} + } + + //拖动条拖动事件监听器 + public interface DragBar { + public void start(double progress);//开始 (开始拖动) + public void update(double progress);//更新 (正在拖动 进度被改变) + public void end(double progress)//结束 (结束拖动) + + } + + //Root监听器 + public interface RootService { + public void rootService(boolean isConnect); + } + + //绘制监听器 + public static abstract class Draw { + //第一帧调用初始化 + //返回true代表初始化完成开始下一帧更新 + //返回false代表初始化失败将锁定在此帧一直初始化并检查直到返回true才开始下一帧更新 + public abstract boolean Start(Canvas canvas);//第一帧 + //每一帧调用更新 + //返回true代表更新完成开始下一帧更新 + //返回false代表更新失败会跳转到Start函数检查是否初始化完成 + public abstract boolean Update(Canvas canvas);//每帧 + public void End(SurfaceHolder holder){};//渲染线程结束 + //更新画布大小时调用 + public void UpdateCanvasSize(SurfaceHolder holder, int format, int width, int height){}; + } + + //微验网络验证监听器 + public interface WY2FA { + //登录成功 卡密 到期时间 远程变量 + public void success(String kami,String expireTime,HashMap field);//登录成功 + + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiDocument.java b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiDocument.java new file mode 100644 index 0000000..a1c99dd --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiDocument.java @@ -0,0 +1,34 @@ +package com.bytecat.algui.AlguiManager; +import com.bytecat.algui.AlguiTools.AlguiToolNetwork; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2025/01/05 08:39 + */ +public class AlguiDocument { + + public static final String TAG = "AlguiDocument"; + + private static final String api ="http://wdan.tangdouz.com/?"; + private static final String key ="oYYW_6Z-62s_yLNjFY3eEStCiaUY"; + + + //写 + public static String getWrite(String fileName, String value) { + return String.format("%sf=%s&cz=w&nr=%s&key=%s", api, fileName, value, key); + } + //读 + public static String getRead(String fileName) { + return String.format("%sf=%s&cz=r&key=%s", api, fileName, key); + } + //删 + public static String getDelete(String fileName) { + return String.format("%sf=%s&cz=d&key=%s", api, fileName, key); + } + //增 + public static String getAdd(String fileName, String value) { + return String.format("%sf=%s&cz=a&nr=%s&key=%s&return=syso", api, fileName, value, key); + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiLog.java b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiLog.java new file mode 100644 index 0000000..df40e2f --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiLog.java @@ -0,0 +1,205 @@ +package com.bytecat.algui.AlguiManager; +import android.content.Context; +import android.os.FileObserver; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import com.bytecat.algui.AlguiTools.AlguiToolFile; +import com.bytecat.algui.AlguiWindows.AlguiWinConsole; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/31 10:37 + * @Describe Algui日志 + */ +public class AlguiLog { + + public static final String TAG = "AlguiLog"; + private static Context aContext; + private static final String fileName="AlguiByteCat.log";//日志文件名 + private static String ALGUILOGFILE = "/data/user/0/com.bytecat.algui/cache/" + fileName; //默认日志文件路径 + private static boolean LOG_ENABLED = true;//日志总开关 + private static boolean LOG_REPEAT=true;//是否写入重复日志 + private static boolean isOne = true;//第一次输出log清除历史log + private static AlguiWinConsole Console;//log控制台窗口 + private static Set loggedEntries = new HashSet<>(); // 用于存储已写入的日志 + private static FileObserver fileObserver; + + public static void init(Context c) { + aContext = c; + if (aContext != null) + ALGUILOGFILE = aContext.getCacheDir().getAbsolutePath() + "/" + fileName; + } + // 设置日志开关 + public static void setLogEnabled(boolean enabled) { + LOG_ENABLED = enabled; + if (!LOG_ENABLED) { + clearLog(); + } + } + //设置日志是否可重复 + public static void setLogRepeatable(boolean isR) { + LOG_REPEAT = isR; + if (isR) { + loggedEntries.clear(); + } + } + //获取LOG控制台窗口 + public static AlguiWinConsole getLogConsole(final Context aContext) { + if (Console == null) { + if (isOne) {//清理历史日志 + clearLog(); + isOne = false; + } + Console = new AlguiWinConsole(aContext); + Console.setCatTitle("Algui日志"); + //监听日志文件 写入到控制台 + final File fileToWatch = getLogFile(); + String newContent = AlguiToolFile.readContents(fileToWatch.getAbsolutePath(), null); + if (newContent != null) { + + Console.getByteText().setCatText(newContent); + Console.getByteWindow().updateWin(); + } + + fileObserver = new FileObserver(ALGUILOGFILE, FileObserver.MODIFY) { + @Override + public void onEvent(int event, String path) { + //文件被修改 + //if (event == FileObserver.MODIFY) { + final String newContent = AlguiToolFile.readContents(fileToWatch.getAbsolutePath(), null); + if (newContent != null) { + Console.getByteText().post(new Runnable() { + @Override + public void run() { + Console.getByteText().setText(newContent); + } + }); + } + //} + } + }; + fileObserver.startWatching(); + } + return Console; + } + + + + + + //获取日志文件 + public static File getLogFile() { + + File logFile = new File(ALGUILOGFILE); + + // 检查文件的父目录是否存在,如果不存在则创建 + /* File parentDir = logFile.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + if (!parentDir.mkdirs()) { + return null; + } + }*/ + + //检查文件是否存在,如果不存在则创建 + if (!logFile.exists()) { + try { + logFile.createNewFile(); + } catch (IOException e) { + return null; + } + } + + return logFile; + } + + + + //将日志写入文件 + private static boolean writeLogToFile(String logEntry) { + try { + File logFile = getLogFile(); + if (logFile == null)return false; + BufferedWriter writer = new BufferedWriter(new FileWriter(logFile, true)); // 追加模式 + writer.write(logEntry); + writer.newLine(); // 换行 + writer.close(); + return true; + } catch (IOException e) { + Log.e(TAG, "Failed to write log to file", e); + } + return false; + } + //清除日志 + public static void clearLog() { + try { + File logFile = getLogFile(); + if (logFile == null)return; + FileOutputStream fos = new FileOutputStream(logFile); + fos.write(new byte[0]); // 清空文件内容 + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + //按级别并格式化写入日志消息 + public static void send(String level, String tag, String format, Object... args) { + if (!LOG_ENABLED) return; + if (isOne) { + clearLog();//清除历史 + isOne = false; + } + + String logMessage = String.format(format, args); + if (!LOG_REPEAT) + if (loggedEntries.contains(tag + logMessage)) { + return; //如果日志已经存在,则跳过写入 + } + long currentTimeMillis = System.currentTimeMillis(); + Date date = new Date(currentTimeMillis); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + String time= sdf.format(date); + String logEntry = String.format("[%s] [%s] [%s] %s", time, level, tag, logMessage); + + if (writeLogToFile(logEntry)) { + if (!LOG_REPEAT) + loggedEntries.add(tag + format); + } + } + + // 调试日志 + public static void d(String tag, String format, Object... args) { + send("DEBUG", tag, format, args); + } + + // 信息日志 + public static void i(String tag, String format, Object... args) { + send("INFO", tag, format, args); + } + + // 警告日志 + public static void w(String tag, String format, Object... args) { + send("WARN", tag, format, args); + } + + // 错误日志 + public static void e(String tag, String format, Object... args) { + send("ERROR", tag, format, args); + } + + // 致命错误日志 + public static void f(String tag, String format, Object... args) { + send("FATAL", tag, format, args); + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiObjectManager.java b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiObjectManager.java new file mode 100644 index 0000000..889b5dd --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiManager/AlguiObjectManager.java @@ -0,0 +1,73 @@ +package com.bytecat.algui.AlguiManager; +import android.view.View; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import java.util.ArrayList; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/24 00:24 + * @Describe Alguu全局对象池(弃用) + */ +public class AlguiObjectManager { + + public static final String TAG = "AlguiObjectManager"; + + private static final ArrayList AlguiViews = new ArrayList<>(); + + //添加视图对象 + public static void addView(View... views) { + for (View v:views) { + if (v != null) { + AlguiViews.add(v); + } + } + } + //获取指定视图类的所有对象 + public static ArrayList getView(String tag) { + ArrayList views=new ArrayList<>(); + for (View v : AlguiViews) { + if (v != null) { + Object tobj =v.getTag(); + if (tobj instanceof String) { + String t = (String)tobj; + if (t.equals(tag)) { + views.add(v); + } + } + } + } + return views; + } + + //设置所有文本点击颜色 + public static void setAlguiTextClickColor(final int... colors) { + final ArrayList views = (ArrayList)(getView(AlguiViewText.TAG)); + for (final AlguiViewText v:views) { + if (v != null) { + v.setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + for (final AlguiViewText u:views) { + if (u!= null) { + u.setCatBackColor(0); + } + } + v.setCatBackColor(colors); + } + } + ); + } + } + } + //设置所有文本大小 + public static void setAlguiTextSize(final float size) { + final ArrayList views = (ArrayList)(getView(AlguiViewText.TAG)); + for (final AlguiViewText v:views) { + if (v != null) { + v.setCatTextSize(size); + + } + } + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiLinkMovementMethod.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiLinkMovementMethod.java new file mode 100644 index 0000000..e508c1b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiLinkMovementMethod.java @@ -0,0 +1,70 @@ +package com.bytecat.algui.AlguiTools; + +/** + * @Author 皓月当空 + * @Date 2025/01/30 21:26 + */ +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.text.Selection; +import android.text.Spannable; +import android.text.method.LinkMovementMethod; +import android.text.method.MovementMethod; +import android.text.style.ClickableSpan; +import android.text.style.URLSpan; +import android.view.MotionEvent; +import android.widget.TextView; + +public class AlguiLinkMovementMethod extends LinkMovementMethod { + private static AlguiLinkMovementMethod instance; + + public static MovementMethod getInstance() { + if (instance == null) { + instance = new AlguiLinkMovementMethod(); + } + return instance; + } + + @Override + public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { + int action = event.getAction(); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { + int x = (int) event.getX(); + int y = (int) event.getY(); + + x -= widget.getTotalPaddingLeft(); + y -= widget.getTotalPaddingTop(); + + x += widget.getScrollX(); + y += widget.getScrollY(); + + int line = widget.getLayout().getLineForVertical(y); + int off = widget.getLayout().getOffsetForHorizontal(line, x); + + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + if (action == MotionEvent.ACTION_UP) { + if (link[0] instanceof URLSpan) { + URLSpan urlSpan = (URLSpan) link[0]; + Context context = widget.getContext(); + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlSpan.getURL())); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } else { + link[0].onClick(widget); + } + } else if (action == MotionEvent.ACTION_DOWN) { + Selection.setSelection(buffer, + buffer.getSpanStart(link[0]), + buffer.getSpanEnd(link[0])); + } + return true; + } else { + Selection.removeSelection(buffer); + } + } + return super.onTouchEvent(widget, buffer, event); + } +} + diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolAiTTS.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolAiTTS.java new file mode 100644 index 0000000..ef8edea --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolAiTTS.java @@ -0,0 +1,116 @@ +package com.bytecat.algui.AlguiTools; + + +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import com.bytecat.algui.AlguiTools.AlguiToolNetwork; +import java.util.HashMap; +import java.util.Map; +import org.json.JSONObject; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/19 02:12 + * @Describe Algui AI文本转语音 + */ +public class AlguiToolAiTTS { + + public static final String TAG = "AlguiAI"; + + //声音模型 + public static final String 女声_普通话_Xiaoxiao = "zh-CN-XiaoxiaoNeural"; // [普通话] Xiaoxiao 女 + public static final String 女声_普通话_Xiaoyi = "zh-CN-XiaoyiNeural"; // [普通话] Xiaoyi 女 + public static final String 女声_辽宁方言_Xiaobei = "zh-CN-liaoning-XiaobeiNeural"; // [辽宁方言] Xiaobei 女 + public static final String 女声_陕西方言_Xiaoni = "zh-CN-shaanxi-XiaoniNeural"; // [陕西方言] Xiaoni 女 + public static final String 女声_粤语_HiuGaai = "zh-HK-HiuGaaiNeural"; // [粤语] HiuGaai 女 + public static final String 女声_粤语_HiuMaan = "zh-HK-HiuMaanNeural"; // [粤语] HiuMaan 女 + public static final String 男声_港式英语_Yan = "en-HK-YanNeural"; // [港式英语] Yan 男 + public static final String 男声_普通话_Yunjian = "zh-CN-YunjianNeural"; // [普通话] Yunjian 男 + public static final String 男声_普通话_Yunxi = "zh-CN-YunxiNeural"; // [普通话] Yunxi 男 + public static final String 男声_普通话_Yunxia = "zh-CN-YunxiaNeural"; // [普通话] Yunxia 男 + public static final String 男声_普通话_Yunyang = "zh-CN-YunyangNeural"; // [普通话] Yunyang 男 + public static final String 男声_粤语_WanLung = "zh-HK-WanLungNeural"; // [粤语] WanLung 男 + public static final String 男声_港式英语_Sam = "en-HK-SamNeural"; // [港式英语] Sam 男 + public static final String 女声_美式英语_Ana = "en-US-AnaNeural"; // [美式英语] Ana 女 + public static final String 女声_美式英语_Aria = "en-US-AriaNeural"; // [美式英语] Aria 女 + public static final String 女声_美式英语_Ava = "en-US-AvaNeural"; // [美式英语] Ava 女 + public static final String 女声_美式英语_Emma = "en-US-EmmaNeural"; // [美式英语] Emma 女 + public static final String 女声_美式英语_Jenny = "en-US-JennyNeural"; // [美式英语] Jenny 女 + public static final String 女声_美式英语_Michelle = "en-US-MichelleNeural"; // [美式英语] Michelle 女 + public static final String 女声_英式英语_Libby = "en-GB-LibbyNeural"; // [英式英语] Libby 女 + public static final String 女声_英式英语_Maisie = "en-GB-MaisieNeural"; // [英式英语] Maisie 女 + public static final String 女声_英式英语_Sonia = "en-GB-SoniaNeural"; // [英式英语] Sonia 女 + public static final String 女声_日语_Nanami = "ja-JP-NanamiNeural"; // [日语] Nanami 女 + public static final String 女声_韩语_SunHi = "ko-KR-SunHiNeural"; // [韩语] SunHi 女 + public static final String 男声_美式英语_Andrew = "en-US-AndrewNeural"; // [美式英语] Andrew 男 + public static final String 男声_美式英语_Brian = "en-US-BrianNeural"; // [美式英语] Brian 男 + public static final String 男声_美式英语_Christopher = "en-US-ChristopherNeural"; // [美式英语] Christopher 男 + public static final String 男声_美式英语_Eric = "en-US-EricNeural"; // [美式英语] Eric 男 + public static final String 男声_美式英语_Guy = "en-US-GuyNeural"; // [美式英语] Guy 男 + public static final String 男声_美式英语_Roger = "en-US-RogerNeural"; // [美式英语] Roger 男 + public static final String 男声_美式英语_Steffan = "en-US-SteffanNeural"; // [美式英语] Steffan 男 + public static final String 男声_英式英语_Ryan = "en-GB-RyanNeural"; // [英式英语] Ryan 男 + public static final String 男声_英式英语_Thomas = "en-GB-ThomasNeural"; // [英式英语] Thomas 男 + public static final String 男声_日语_Keita = "ja-JP-KeitaNeural"; // [日语] Keita 男 + public static final String 男声_韩语_Hyunsu = "ko-KR-HyunsuNeural"; // [韩语] Hyunsu 男 + public static final String 男声_韩语_InJoon = "ko-KR-InJoonNeural"; // [韩语] InJoon 男 + +/* + private static final String TAGP = "AES"; + private static final String pQ8rS9tU0vW1xY = "U2FsdGVkX18iSokkT3f/UJFikV7bYI+Uu6rR1tqlLijtGBJNpjYkJH+NWYAn5jwdQmaf5iILCJj9kIxKXgIxWBLPlmV182dCX+xkDMU046k30oBlObzASB0NroBDF01VpmYWIKDZh4XPAleqbPn8gg=="; + private static final String aBcD1eFgH2iJkL = "U2FsdGVkX1/Vpm9jyqYxEFW4+0rr//grGQhPAbLBzZqvRdwYkN/fp0cm32rRVKmJoz8jgZmKNZ5pOc9PcL1TxuRc/3nJpHNjkYUdar4TxT1or153BgjBhgC4syhITqh+"; + private static final String jK6lM7nO8pQ9rS = "6f5c8a9b1e8f70d7e84f1d7c55b9079d7b1b73c12b4e9f9b82d65a763e5b7a91"; + static{ + try { + S_SERVER = new String(qR7s9_T3hXzYkLmN( + qR7s9_T3hXzYkLmN(Base64.decode(pQ8rS9tU0vW1xY,Base64.DEFAULT), jK6lM7nO8pQ9rS), + new String(qR7s9_T3hXzYkLmN(Base64.decode(aBcD1eFgH2iJkL,Base64.DEFAULT), jK6lM7nO8pQ9rS),StandardCharsets.UTF_8)),StandardCharsets.UTF_8); + AlguiLog.d(S_SERVER); + } catch (Exception e) { + AlguiLog.d(e.getMessage()); + } + }*/ + + private AlguiToolAiTTS() + { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + + + //AI说话 参数:说什么,声音模型 + public static void speak(String content, String sound) { + String v = String.format("character=%s&text=%s", + sound==null||sound.isEmpty()?女声_陕西方言_Xiaoni:sound, + content==null||content.isEmpty()?"你没有告诉我要说什么鸭":content + ); + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + headers.put("Accept", "application/json"); + AlguiToolNetwork.POST("https://ai.bingal.com/cn/ai-tts/", v, headers , new AlguiToolNetwork.NetworkCallback() { + @Override + public void onSuccess(String response) { + try { + JSONObject jsonObject = new JSONObject(response); + JSONObject dataObject = jsonObject.getJSONObject("data"); + String url = dataObject.getString("url"); + if (url != null) { + AlguiToolAudio.playAudio_Url(url); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onFailure(String error) { + AlguiLog.e(TAG,"AI说话异常: " + error); + } + }); + } + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolApp.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolApp.java new file mode 100644 index 0000000..0b625d1 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolApp.java @@ -0,0 +1,295 @@ +package com.bytecat.algui.AlguiTools; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.graphics.drawable.Drawable; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import com.bytecat.algui.BuildConfig; +import java.io.DataOutputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/19 02:12 + * @Describe Algui APP工具 + */ +public class AlguiToolApp { + + public static final String TAG = "AlguiToolApp"; + + // 检测当前是否有网络连接 + public static boolean isNetworkAvailable(Context context) { + if (context == null) { + return false; + } + + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivityManager != null) { + NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); + return activeNetworkInfo != null && activeNetworkInfo.isConnected(); + } + return false; + } + + //返回桌面 + public static void backToDesktop(Context context) { + Intent mHomeIntent = new Intent(Intent.ACTION_MAIN); + mHomeIntent.addCategory(Intent.CATEGORY_HOME); + mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + context.startActivity(mHomeIntent); + }; + + + //检查当前应用程序是否处于前台 + public static boolean isAppInForeground() { + ActivityManager.RunningAppProcessInfo runningAppProcessInfo = new ActivityManager.RunningAppProcessInfo(); + ActivityManager.getMyMemoryState(runningAppProcessInfo); + return runningAppProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + } + + //检测当前应用程序是否已授予ROOT权限 + public static boolean isRootEnabled() { + Process process = null; + try { + process = Runtime.getRuntime().exec("su"); + OutputStream outputStream = process.getOutputStream(); + outputStream.write("echo \"test\" >/dev/null\n".getBytes()); + outputStream.flush(); + outputStream.close(); + int exitCode = process.waitFor(); + return (exitCode == 0); + } catch (Exception e) { + // 忽略异常 + } finally { + if (process != null) { + try { + process.destroy(); + } catch (Exception e) { + // 忽略异常 + } + } + } + return false; + } + + + /** + * 获得root权限 + * @param context 上下文 + * @return + */ + public static boolean getRootPermission(Context context) { + String packageCodePath = context.getPackageCodePath(); + Process process = null; + DataOutputStream os = null; + try { + String cmd = "chmod 777 " + packageCodePath; + process = Runtime.getRuntime().exec("su"); + os = new DataOutputStream(process.getOutputStream()); + os.writeBytes(cmd + "\n"); + os.writeBytes("exit\n"); + os.flush(); + process.waitFor(); + } catch (Exception e) { + return false; + } finally { + try { + if (os != null) { + os.close(); + } + process.destroy(); + } catch (Exception e) { + e.printStackTrace(); + } + } + return true; + } + + + /** + * 检测APP是否安装 + * + * @param packageName + * @return + */ + public boolean isInstalled(Context context, String packageName) { + PackageManager manager = context.getPackageManager(); + //获取所有已安装程序的包信息 + List installedPackages = manager.getInstalledPackages(0); + if (installedPackages != null) { + for (PackageInfo info : installedPackages) { + if (info.packageName.equals(packageName)) + return true; + } + } + return false; + } + + + /** + * 获取版本号 + * + * @return 当前应用的版本号 + */ + public static int getVersionCode(Context context) { + try { + PackageManager manager = context.getPackageManager(); + PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0); + int versionCode = info.versionCode; + return versionCode; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 获取版本名字 + * + * @return 当前应用的版本号 + */ + public static String getVersionName(Context context) { + try { + PackageManager manager = context.getPackageManager(); + PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0); + String version = info.versionName; + return version; + } catch (Exception e) { + e.printStackTrace(); + return "0.0"; + } + } + + /** + * 获取apk的名称 + * @param context 上下文 + * @return String app名称 + */ + public static String getAppName(Context context) { + try { + PackageManager e = context.getPackageManager(); + PackageInfo packageInfo = e.getPackageInfo(context.getPackageName(), 0); + int labelRes = packageInfo.applicationInfo.labelRes; + return context.getResources().getString(labelRes); + } catch (PackageManager.NameNotFoundException var4) { + var4.printStackTrace(); + return "unKnown"; + } + } + + /** + * 获取应用图标 + * @param context 上下文 + * @param packageName 包名 + * @return + */ + public static Drawable getAppIcon(Context context, String packageName) { + PackageManager pm = context.getPackageManager(); + Drawable appIcon = null; + try { + ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 0); + appIcon = applicationInfo.loadIcon(pm); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return appIcon; + } + + // 获取应用包名 + public static String getAppPackageName(Context context) { + return context.getPackageName(); + } + + // 判断应用是否为系统应用 + public static boolean isSystemApp(Context context) { + ApplicationInfo applicationInfo = context.getApplicationInfo(); + return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + // 获取应用的签名信息 + public static String getAppSignature(Context context) { + try { + PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + Signature[] signatures = packageInfo.signatures; + if (signatures.length > 0) { + Signature signature = signatures[0]; + return signature.toCharsString(); + } + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return "null"; + } + + + + //获取当前应用的UID + public static int getAppUid(Context context) { + return context.getApplicationInfo().uid; + } + + //检测当前设备的哪些应用与自己当前应用的UID相同,并返回应用名称列表 + public static List getSameUidAppNames(Context context) { + int myUid = getAppUid(context); + PackageManager packageManager = context.getPackageManager(); + List appList = packageManager.getInstalledApplications(PackageManager.GET_META_DATA); + List sameUidAppNames = new ArrayList<>(); + + for (ApplicationInfo appInfo : appList) { + if (appInfo.uid == myUid && !appInfo.packageName.equals(context.getPackageName())) { + String appName = appInfo.loadLabel(packageManager).toString(); + sameUidAppNames.add(appName); + } + } + + return sameUidAppNames; + } + + //获取当前应用的入口Activity名称 + public static String getLauncherActivityName(Context context) { + PackageManager pm = context.getPackageManager(); + Intent intent = pm.getLaunchIntentForPackage(context.getPackageName()); + if (intent == null) { + return null; + } + ComponentName cn = intent.getComponent(); + return cn.getClassName(); + } + + /** + * 服务是否在运行 + * @param context + * @param className + * @return + */ + public static boolean isServiceRunning(Context context, String className) { + boolean isRunning = false; + ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List servicesList = activityManager.getRunningServices(Integer.MAX_VALUE); + for (RunningServiceInfo si : servicesList) { + if (className.equals(si.service.getClassName())) { + isRunning = true; + } + } + return isRunning; + } + + + //检测调试模式 + public static boolean isDebugMode(Context context) { + return BuildConfig.DEBUG || (0 != (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)); + } + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolAudio.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolAudio.java new file mode 100644 index 0000000..95cfd5b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolAudio.java @@ -0,0 +1,194 @@ +package com.bytecat.algui.AlguiTools; +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.util.Base64; +import com.bytecat.algui.AlguiManager.AlguiLog; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/16 03:12 + * @Describe 音频工具 + */ +public class AlguiToolAudio { + + public static final String TAG = "AlguiToolAudio"; + + private AlguiToolAudio() { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + + + //将base64编码音频下载到本地音频文件 (参数2传入绝对路径) + public static File audioBase2file(String base64, String filePath) { + if (base64 == null || filePath == null) { + return null; + } + byte[] decodedAudio = Base64.decode(base64, Base64.DEFAULT); // 解码Base64编码的音频数据 + try { + File audioFile = new File(filePath); // 创建音频文件对象 + FileOutputStream outputStream = new FileOutputStream(audioFile); // 创建文件输出流,用于将音频数据写入文件 + outputStream.write(decodedAudio); // 将音频数据写入文件 + outputStream.close(); // 关闭文件输出流 + return audioFile; // 返回音频文件对象 + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + //通用播放音频方法 + //支持:网络音频,base64音频,本地文件音频,文件名(自动识别为assets文件夹的音频) + public static MediaPlayer playAudio(Context context, String Url_Base64_FilePath) { + MediaPlayer m=null; + if (Url_Base64_FilePath != null) { + //字符串开头是http或https为网络资源 + if (Url_Base64_FilePath.startsWith("http://") || Url_Base64_FilePath.startsWith("https://")) { + m = playAudio_Url(Url_Base64_FilePath); + //对于base64资源检测长度 + } else if (Url_Base64_FilePath.length() > 32 + 16) { + m = playAudio_Base64(context, Url_Base64_FilePath); + //其它情况默认识别为本地资源 + } else { + m = playAudio_File(context, Url_Base64_FilePath); + } + } + return m; + } + + //播放base64音频 + private static int fileID=0;//全局音频文件ID + private static final Map audioBase64Map = new HashMap<>(); //已缓存的base64音频列表 + public static MediaPlayer playAudio_Base64(Context context, String base64) { + MediaPlayer m=null; + if (base64 != null && context != null) { + String filePath = audioBase64Map.get(base64); //查找文件路径 + try { + if (filePath == null) { + //如果文件路径不存在,则下载并保存 + filePath = context.getCacheDir().getAbsolutePath() + "/AlguiAudio" + fileID + ".ogg"; //构造文件路径 + if (audioBase2file(base64, filePath) == null) //下载并保存文件 + return m;//失败结束 + AlguiToolFileEnc.encryptFile(filePath); //进行加密 + audioBase64Map.put(base64, filePath); //存入映射表 + fileID++; //增加全局文件ID,避免文件名重复 + } + AlguiToolFileEnc.decryptFile(filePath); //解密 + m = playAudio_File(context, filePath); //播放音频 + AlguiToolFileEnc.encryptFile(filePath); //加密 + } catch (Exception e) { + //捕获加密解密过程中可能的异常,但不应影响播放 + e.printStackTrace(); + } + } + return m; + } + + //播放指定路径的音频文件 + public static MediaPlayer playAudio_File(Context context, String filePath) { + MediaPlayer mediaPlayer=null; + if (filePath != null) { + try { + mediaPlayer = new MediaPlayer(); // 创建媒体播放器对象 + mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // 设置媒体流类型为音乐流 + //设置数据源 + if (filePath.toLowerCase().startsWith("/assets/") || filePath.toLowerCase().startsWith("assets/") || !filePath.contains("/")) { + //对于assets文件夹下的文件 + //查找最后一个/的位置 + int lastSlashIndex = filePath.lastIndexOf('/'); + //获取最后一个/之后的子字符串(文件名) + if (lastSlashIndex != -1) { + filePath = filePath.substring(lastSlashIndex + 1); + } + AssetFileDescriptor afd = context.getAssets().openFd(filePath); + mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); + } else { + //其它情况为本地路径文件 + mediaPlayer.setDataSource(filePath); + } + + mediaPlayer.prepare(); // 准备媒体播放器 + mediaPlayer.start(); // 开始播放音频 + mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // 播放完成后释放资源 + mp.release(); + } + }); + + + } catch (IOException e) { + e.printStackTrace(); + mediaPlayer.release(); + mediaPlayer = null; + } + } + return mediaPlayer; + } + + + + // 播放网络音频 + public static MediaPlayer playAudio_Url(String audioUrl) { + MediaPlayer mediaPlayer=null; + // 检查音频URL是否为空或无效 + if (audioUrl != null) { + // 创建MediaPlayer实例 + mediaPlayer = new MediaPlayer(); + + try { + // 设置数据源为网络音频URL + mediaPlayer.setDataSource(audioUrl); + // 异步准备音频 + mediaPlayer.prepare(); + // 设置音频准备完成的监听器 + mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mp) { + mp.start(); // 准备完成后开始播放 + } + }); + // 设置音频播放完成的监听器 + mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + mp.release(); // 播放完成后释放资源 + } + }); + // 设置音频播放错误的监听器 + mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + AlguiLog.e(TAG,"播放网络音频失败!错误代码: " + what); + mp.release(); // 出现错误时释放资源 + return true; // 错误已处理 + } + }); + + } catch (IOException e) { + // 处理IO异常 + e.printStackTrace(); + AlguiLog.e(TAG,"在播放网络音频时发生了IO错误:" + e.getMessage()); + mediaPlayer.release(); // 释放资源 + mediaPlayer=null; + } catch (Exception e) { + // 处理其他异常 + e.printStackTrace(); + AlguiLog.e(TAG,"在播放网络音频时发生了错误:" + e.getMessage()); + mediaPlayer.release(); // 释放资源 + mediaPlayer=null; + } + } + return mediaPlayer; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolCache.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolCache.java new file mode 100644 index 0000000..2bfcb87 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolCache.java @@ -0,0 +1,70 @@ +package com.bytecat.algui.AlguiTools; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/30 02:48 Algui缓存工具 + */ +import android.content.Context; +import android.content.SharedPreferences; + +public class AlguiToolCache { + + public static final String TAG = "AlguiToolCach"; + + private static final String cacheFileName="Algui"; + + //获取缓存文件对象 + private static SharedPreferences getSharedPreferences(Context context) { + return context.getSharedPreferences(cacheFileName, Context.MODE_PRIVATE); + } + + //保存数据到缓存文件 变量名,数据 + public static boolean saveData(Context context, String variableName, Object data) { + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + + if (data instanceof String) { + editor.putString(variableName, (String) data); + } else if (data instanceof Integer) { + editor.putInt(variableName, (Integer) data); + } else if (data instanceof Boolean) { + editor.putBoolean(variableName, (Boolean) data); + } else if (data instanceof Float) { + editor.putFloat(variableName, (Float) data); + } else if (data instanceof Long) { + editor.putLong(variableName, (Long) data); + } else { + return false; // 不支持存储其他类型 + } + + return editor.commit(); + } + + //从缓存文件读取数据 变量名,默认值 + public static Object getData(Context context, String variableName, Object defaultValue) { + SharedPreferences prefs = getSharedPreferences(context); + + if (defaultValue instanceof String) { + return prefs.getString(variableName, (String) defaultValue); + } else if (defaultValue instanceof Integer) { + return prefs.getInt(variableName, (Integer) defaultValue); + } else if (defaultValue instanceof Boolean) { + return prefs.getBoolean(variableName, (Boolean) defaultValue); + } else if (defaultValue instanceof Float) { + return prefs.getFloat(variableName, (Float) defaultValue); + } else if (defaultValue instanceof Long) { + return prefs.getLong(variableName, (Long) defaultValue); + } + + return null; // 不支持其他类型 + } + + //删除缓存文件指定变量名的数据 + public static boolean deleteData(Context context, String variableName) { + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + editor.remove(variableName); + return editor.commit(); + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolFile.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolFile.java new file mode 100644 index 0000000..dea1b59 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolFile.java @@ -0,0 +1,420 @@ +package com.bytecat.algui.AlguiTools; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/31 09:34 + * @Describe Algui文件工具 + */ +import android.content.Context; +import android.os.Environment; +import android.text.TextUtils; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +public class AlguiToolFile { + + public static final String TAG = "AlguiToolFile"; + + + + //==========================获取内部、外部文件存储路径============================= + public static String getRootPath(){ + // /storage/emulated/0 + return Environment.getExternalStorageDirectory().getAbsolutePath(); + } + + public static String getAppRootPth(Context context){ + // /storage/emulated/0/Android/data/pack_name/files + return context.getExternalFilesDir("").getAbsolutePath(); + } + + public static String getInternalPath(){ + // /data + return Environment.getDataDirectory().getAbsolutePath(); + } + + public static String getInternalAppPath(Context context){ + // /data/user/0/packname/files + return context.getFilesDir().getAbsolutePath(); + } + + //====================创建文件、文件夹================================ + public static boolean createFile(String path, String fileName){ + File file = new File(path+"/"+fileName); + + if(!file.exists()){ + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + return true; + }else{ + // + return false; + } + } + + public static boolean createDirs(String folder){ + File file = new File(folder); + + if(!file.exists()) { + file.mkdirs(); + return true; + } + return false; + } + + //===================删除文件夹及其内部文件、文件夹===================== + public static void deleteDir(String dir){ + File file = new File(dir); + if(file.exists()){ + deleteDirWithFile(file); + } + } + + private static void deleteDirWithFile(File file) { + if(!file.isDirectory() || !file.exists()) { + return; + } + if(file.list().length>0){ + for(File f : file.listFiles()){ + if(f.isFile()){ + f.delete();//delete all files + }else if(f.isDirectory()){ + deleteDirWithFile(f); + } + } + } + + file.delete(); + } + + public static boolean deleteFile(String path){ + File file = new File(path); + if(file.exists()&&file.isFile()){ + file.delete(); + return true; + } + + return false; + } + + //=========================复制、移动文件=========================== + public static void copyFile(String oldPath, String newPath){ + byte[] bytes = readBytes(oldPath); + getFileFromBytes(bytes, newPath); + } + + public static void moveFile(String oldPath, String newPath){ + //先复制文件,然后删除原文件 + copyFile(oldPath, newPath); + deleteFile(oldPath); + } + + public static int copy(String src, String dest) { + int retVal = 0;//0: 成功; -1:失败 + InputStream from = null; + OutputStream to = null; + try { + from = new FileInputStream(src); + to = new FileOutputStream(dest); + byte buffer[] = new byte[1024 * 8]; + int length; + while ((length = from.read(buffer)) != -1) { + to.write(buffer, 0, length); + } + } catch (Exception ex) { + ex.printStackTrace(); + retVal = -1; + } finally { + if (from != null) { + try { + from.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (to != null) { + try { + to.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + File file = new File(dest); + if (file.exists()) { + file.setLastModified(System.currentTimeMillis()); + } + return retVal; + } + + //========================获取文件夹下文件信息============================ + public static int getFilesNumber(String dir){ + File file = new File(dir); + + return file.listFiles().length; + } + + public static String[] getFilesList(String dir){ + File file = new File(dir); + + return file.list(); + } + + //===========================重命名======================= + public static void changeFileDirName(String path, String oldName, String newName){ + File oldFile = new File(path+"/"+oldName); + File newFile = new File(path+"/"+newName); + + oldFile.renameTo(newFile); + } + + //========================read and write content=========================== + public static void writeToFile(String content, String path, String fileName){ + File file = new File(path+fileName); + if(!file.exists()){ + createFile(path, fileName); + } + + RandomAccessFile randomAccessFile; + try { + randomAccessFile = new RandomAccessFile(file, "rw"); + randomAccessFile.seek(0);//rewrite + randomAccessFile.write(content.getBytes()); + + randomAccessFile.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static File getFileFromBytes(byte[] bytes, String outputFile) { + BufferedOutputStream stream = null; + File file = null; + try { + file = new File(outputFile); + FileOutputStream fileOutputStream = new FileOutputStream(file); + stream = new BufferedOutputStream(fileOutputStream); + stream.write(bytes); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + return file; + } + + public static String readContents(String path, String format){ + if(format==null){//default + format="utf-8"; + } + + File file = new File(path); + if(!file.exists()){ + return null; + } + + FileInputStream inputStream = null; + try { + inputStream = new FileInputStream(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + InputStreamReader inputStreamReader = null; + try { + inputStreamReader = new InputStreamReader(inputStream, format);//'utf-8' 'GBK' + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + BufferedReader reader = new BufferedReader(inputStreamReader); + StringBuilder builder = new StringBuilder(""); + String line; + try { + while((line=reader.readLine())!=null){ + builder.append(line); + builder.append("\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } + return builder.toString(); + } + + public static String readResource(Context context, int id, String format){ + InputStream inputStream = context.getResources().openRawResource(id); + InputStreamReader inputStreamReader = null; + try { + inputStreamReader = new InputStreamReader(inputStream, format);//'utf-8' 'GBK' + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + BufferedReader reader = new BufferedReader(inputStreamReader); + StringBuilder builder = new StringBuilder(""); + String line; + try { + while((line=reader.readLine())!=null){ + builder.append(line); + builder.append("\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } + return builder.toString(); + } + + public static byte[] readBytes(String path){ + File file = new File(path); + if(!file.exists()){ + return null; + } + + FileInputStream inputStream = null; + try { + inputStream = new FileInputStream(file); + long size = inputStream.getChannel().size(); + if(size<=0){ + return null; + } + + byte[] bytes = new byte[inputStream.available()]; + inputStream.read(bytes); + + return bytes; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + //===========================zip/unzip file/dir============================== + /* public static void unZip(String path, String aimPath, String password) throws ZipException { + File file = new File(path); + if(!file.exists()){ + return; + } + + unZipFile(file, aimPath, password); + } + + public static void unZipFile(File file, String aimPath, String password) throws ZipException { + ZipFile zipFile = new ZipFile(file); + zipFile.setFileNameCharset("GBK"); + + if (!zipFile.isValidZipFile()) { + throw new ZipException("压缩文件不合法,可能被损坏."); + } + + if(!TextUtils.isEmpty(aimPath)){ + File destDir = new File(aimPath); + if (destDir.isDirectory() && !destDir.exists()) { + destDir.mkdir(); + } + if (zipFile.isEncrypted()) { + zipFile.setPassword(password.toCharArray()); + } + zipFile.extractAll(aimPath); + }else{//unzip to current path + File parentDir = file.getParentFile(); + unZipFile(file, parentDir.getAbsolutePath(), password); + } + } + + public static boolean zipFile(String path, String aimPath, String password) { + File file = new File(path); + if (!file.exists()) { + return false; + } + + aimPath = buildDestinationZipFilePath(file, aimPath); + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 压缩方式 + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 压缩级别 + if (!TextUtils.isEmpty(password)) { + parameters.setEncryptFiles(true); + parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式 + parameters.setPassword(password.toCharArray()); + } + try { + ZipFile zipFile = new ZipFile(aimPath); + if (file.isDirectory()) { + // 如果不创建目录的话,将直接把给定目录下的文件压缩到压缩文件,即没有目录结构 + File[] subFiles = file.listFiles(); + ArrayList temp = new ArrayList(); + Collections.addAll(temp, subFiles); + zipFile.addFiles(temp, parameters); + } else { + zipFile.addFile(file, parameters); + } + } catch (ZipException e) { + e.printStackTrace(); + } + return true; + } + + private static String buildDestinationZipFilePath(File srcFile, String destParam) { + if (TextUtils.isEmpty(destParam)) { + if (srcFile.isDirectory()) { + destParam = srcFile.getParent() + File.separator + srcFile.getName() + ".zip"; + } else { + String fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf(".")); + destParam = srcFile.getParent() + File.separator + fileName + ".zip"; + } + } else { + createDestDirectoryIfNecessary(destParam); // 在指定路径不存在的情况下将其创建出来 + if (destParam.endsWith(File.separator)) { + String fileName = ""; + if (srcFile.isDirectory()) { + fileName = srcFile.getName(); + } else { + fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf(".")); + } + destParam += fileName + ".zip"; + } + } + return destParam; + } + + private static void createDestDirectoryIfNecessary(String destParam) { + File destDir = null; + if (destParam.endsWith(File.separator)) { + destDir = new File(destParam); + } else { + destDir = new File(destParam.substring(0, destParam.lastIndexOf(File.separator))); + } + if (!destDir.exists()) { + destDir.mkdirs(); + } + }*/ + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolFileEnc.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolFileEnc.java new file mode 100644 index 0000000..bc5ae2b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolFileEnc.java @@ -0,0 +1,110 @@ +package com.bytecat.algui.AlguiTools; + + +import android.util.Log; +import java.io.File; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.security.NoSuchAlgorithmException; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/17 08:45 + * @Describe Algui文件加密解密工具 + */ +public class AlguiToolFileEnc { + + public static final String TAG = "AlguiToolFileEnc"; + + private static final String ALGORITHM = "AES";//使用AES算法 + + private static SecretKey KEY;//存储随机密钥 + //类加载时初始生成随机密钥 + static{ + try { + KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM); + keyGen.init(128); // 使用128位密钥 + KEY = keyGen.generateKey(); + } catch (NoSuchAlgorithmException e) { + + } + } + + private AlguiToolFileEnc() + { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + /** + * 加密文件方法 + * @param filePath 要加密的文件绝对路径 + * @throws Exception 可能抛出的异常,例如文件操作异常或加密异常 + */ + public static void encryptFile(String filePath) throws Exception { + doCrypto(Cipher.ENCRYPT_MODE, filePath); + } + + /** + * 解密文件方法 + * @param filePath 要解密的文件绝对路径 + * @throws Exception 可能抛出的异常,例如文件操作异常或解密异常 + */ + public static void decryptFile(String filePath) throws Exception { + doCrypto(Cipher.DECRYPT_MODE, filePath); + } + + + + /** + * 通用加解密方法 + * @param cipherMode 指定操作模式,Cipher.ENCRYPT_MODE 表示加密,Cipher.DECRYPT_MODE 表示解密 + * @param filePath 要加解密的文件,包含要加密或解密的数据 + * @throws Exception 可能抛出的异常,例如文件操作异常或加解密异常 + */ + public static void doCrypto(int cipherMode, String filePath) throws Exception { + if (filePath == null) { + return; + } + + if(KEY==null){ + //可能被逆 结束程序 + System.exit(0); + } + //获取加密算法实例 + Cipher cipher = Cipher.getInstance(ALGORITHM != null ?ALGORITHM: "AES"); + //初始化设置加解密模式和密钥 + cipher.init(cipherMode, KEY); + + //原文件 + File file = new File(filePath); + //临时文件 + File tempFile = new File(filePath + ".tmp"); + + try (RandomAccessFile raf = new RandomAccessFile(file, "rws"); + FileOutputStream tempOutputStream = new FileOutputStream(tempFile)) { + + //读取原文件的所有字节 + byte[] inputBytes = new byte[(int) raf.length()]; + raf.readFully(inputBytes); + + //执行加密或解密操作 + byte[] outputBytes = cipher.doFinal(inputBytes); + + //将处理后的字节写入临时文件 + tempOutputStream.write(outputBytes); + } + + //替换原文件为加密/解密后的文件 + //删除原文件 + if (!file.delete()) { + throw new RuntimeException("加解密文件-错误:F1 -无法删除原文件"); + } + //将临时文件重命名为原文件 + if (!tempFile.renameTo(file)) { + throw new RuntimeException("加解密文件-错误:F2 -无法重命名原文件"); + } + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolImage.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolImage.java new file mode 100644 index 0000000..b1d44cb --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolImage.java @@ -0,0 +1,505 @@ +package com.bytecat.algui.AlguiTools; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/24 22:36 + * @Describe 图像工具 + */ +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ImageDecoder; +import android.graphics.drawable.AnimatedImageDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.util.Base64; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiManager.AlguiLog; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +public class AlguiToolImage { + + public static final String TAG = "AlguiToolImage"; + + + + //获取图像 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + //注意:回调是为网络图像准备的所以网络图像要在callback回调中获取图像,其它的可以不实现回调因为都是直接返回获取到的图像 + public static Drawable getImage(Context context, String Url_Base64_FilePath, AlguiCallback.Web callback) { + Drawable d=null; + if (Url_Base64_FilePath != null) { + //字符串开头是http或https则设置为网络图片 + if (Url_Base64_FilePath.startsWith("http://") || Url_Base64_FilePath.startsWith("https://")) { + getImageURL(Url_Base64_FilePath, callback); + //对于base64图像检测长度 + } else if (Url_Base64_FilePath.length() > 32 + 16) { + d = getImageBase64(Url_Base64_FilePath); + //其它情况默认识别为本地图像文件 + } else { + d = getImageFile(Url_Base64_FilePath, context); + } + } + return d; + } + + //获取网络图片 + public static void getImageURL(final String url, final AlguiCallback.Web callback) { + if (url == null || callback == null) { + return; + } + final Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (callback != null) + callback.web(msg); + } + }; + new Thread() { + @Override + public void run() { + try { + URL u = new URL(url); + //获取连接 + HttpURLConnection connection = (HttpURLConnection) u.openConnection(); + //使用GET方法访问网络 + connection.setRequestMethod("GET"); + //超时时间 + connection.setConnectTimeout(60000); + //获取返回码 + int code = connection.getResponseCode(); + if (code == 200) { + InputStream inputStream = connection.getInputStream(); + //使用工厂把网络的输入流生产Drawable + Drawable drawable = Drawable.createFromStream(inputStream, "AlguiImage"); + + //利用Message把图片发给Handler + Message msg = Message.obtain(); + msg.obj = drawable; + msg.what = 200; + if (msg.obj != null) + //对于gif则开始动画 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + if (msg.obj instanceof AnimatedImageDrawable) + ((AnimatedImageDrawable) drawable).start(); + handler.sendMessage(msg); + inputStream.close(); + } else { + //服务启发生错误 + handler.sendEmptyMessage(404); + } + } catch (IOException e) { + e.printStackTrace(); + //网络连接错误 + handler.sendEmptyMessage(651); + } + } + }.start(); + } + + //获取本地图像 + //1.可以传入 本地文件路径 例如:/data/user/0/com.bytecat.algui/cache/image.png + //注意:本地文件路径别人手机上没有这个图片,所以这只针对于从网络下载图像到本地,然后引用此下载好的图像 + //2.可以传入 图像文件名 自动在Assets文件夹下搜索此图像文件 + //3.可以传入 项目根目录Assets路径 例如:/assets/image.png + public static Drawable getImageFile(String filePath, Context context) { + Drawable d=null; + if (filePath != null) { + try { + //开头是assets文件夹或者是一个图片文件名则获取assets文件夹图像 + if (filePath.toLowerCase().startsWith("/assets/") || filePath.toLowerCase().startsWith("assets/") || !filePath.contains("/")) { + //查找最后一个/的位置 + int lastSlashIndex = filePath.lastIndexOf('/'); + //获取最后一个/之后的子字符串(图片文件名) + if (lastSlashIndex != -1) { + filePath = filePath.substring(lastSlashIndex + 1); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {//对于安卓9以上 + d = ImageDecoder.decodeDrawable(ImageDecoder.createSource(context.getAssets(), filePath)); + } else { + try { + Bitmap bitmap = BitmapFactory.decodeStream(context.getAssets().open(filePath)); + if (bitmap != null) { + d = new BitmapDrawable(context.getResources(), bitmap); + } + } catch (IOException e) {} + } + } else { + //其它情况为本地路径图片 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {//对于安卓9以上 + d = ImageDecoder.decodeDrawable(ImageDecoder.createSource(new File(filePath))); + } else { + Bitmap bitmap = BitmapFactory.decodeFile(filePath); + if (bitmap != null) { + d = new BitmapDrawable(context.getResources(), bitmap); + } + } + + } + } catch (IOException e) { + d = null; + e.printStackTrace(); + } + } + if (d != null) { + //对于gif则开始动画 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + if (d instanceof AnimatedImageDrawable) + ((AnimatedImageDrawable) d).start(); + } + return d; + } + + + //获取Base64图像 + //对Base64长度有限制,太大可能出现异常 + public static Drawable getImageBase64(String base64String) { + Drawable d=null; + if (base64String != null) { + try { + byte[] decodedBytes = Base64.decode(base64String, Base64.DEFAULT); + InputStream inputStream = new ByteArrayInputStream(decodedBytes); + d = Drawable.createFromStream(inputStream, null); + } catch (IllegalArgumentException e) { + d = null; + e.printStackTrace(); + } + } + if (d != null) { + //对于gif则开始动画 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + if (d instanceof AnimatedImageDrawable) + ((AnimatedImageDrawable) d).start(); + } + return d; + } + + + + //下载图片到本地 + public static File saveDrawableToFile(Context context, Drawable drawable, String filePath) { + if (drawable == null || filePath == null) { + return null; + } + //结尾是分隔符代表没有图片名称 + if (filePath.endsWith("/")) { + filePath = filePath + "AlguiImage.png";//使用默认文件名 + } + + File imageFile = new File(filePath); + String fileName = imageFile.getName();//获取文件名image.png + // 检查路径是否是外部存储目录并且是单个图片文件名则下载到相册 + if ((filePath.startsWith("/storage/emulated/0/") || filePath.startsWith("/mnt/sdcard/")) || !filePath.contains("/")) { + if (!fileName.contains(".")) { + fileName += ".png";//没有扩展名则添加 + } + // 对于 Android 10(API 29)及以上版本,使用 getExternalFilesDir + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + File appSpecificDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); + if (appSpecificDir != null) { + imageFile = new File(appSpecificDir, fileName); + filePath = imageFile.getAbsolutePath(); + } + } else { + // 低版本可以使用公共存储路径 + File downloadDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + if (!downloadDirectory.exists()) { + downloadDirectory.mkdirs(); + } + imageFile = new File(downloadDirectory, fileName); + filePath = imageFile.getAbsolutePath(); + } + } + + + + + //文件已存在则重命名 + if (imageFile.exists()) { + // 获取文件名和文件后缀 + + //获取名称image + String fileBaseName = fileName.contains(".") ? fileName.substring(0, fileName.lastIndexOf(".")) : fileName; + //获取扩展名.png + String fileExtension = fileName.contains(".") ? fileName.substring(fileName.lastIndexOf(".")) : ""; + String path = imageFile.getParent() + "/"; + + int i = 1; + //生成带编号的文件名 直到文件不存在 + while (imageFile.exists()) { + filePath = path + fileBaseName + i + fileExtension; + imageFile = new File(filePath); + i++; + } + } + + + // 将 Drawable 转换为 Bitmap + Bitmap bitmap = drawableToBitmap(drawable); + + // 创建父目录(如果不存在的话) + File parentDir = imageFile.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); + } + + try { + FileOutputStream fos = new FileOutputStream(imageFile); + // 保存为 PNG 格式 + bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.flush(); + AlguiLog.d(TAG, "下载图像完成 路径:" + filePath); + } catch (IOException e) { + imageFile = null; + AlguiLog.d(TAG, "下载图像异常 异常:" + e.getMessage()); + e.printStackTrace(); + } + + return imageFile; + } + + // 将 Bitmap 转换为 Drawable + public static Drawable bitmapToDrawable(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + return new BitmapDrawable(Resources.getSystem(), bitmap); + } + // 将 Drawable 转换为 Bitmap + public static Bitmap drawableToBitmap(Drawable drawable) { + if (drawable == null) { + return null; + } + if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap().copy(Bitmap.Config.ARGB_8888, true); + } + + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + + return bitmap; + } + + //处理图像模糊 + public static Drawable psImageBlur(Drawable image, int radius, Context context) { + //确保不为动态图片并且模糊半径不是负数 + if (image != null && image instanceof BitmapDrawable && radius > 0) { + //不能是 Bitmap.Config.HARDWARE + Bitmap bitmap = ((BitmapDrawable) image).getBitmap().copy(Bitmap.Config.ARGB_8888, true); + + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + int[] pix = new int[w * h]; + bitmap.getPixels(pix, 0, w, 0, 0, w, h); + + int wm = w - 1; + int hm = h - 1; + int wh = w * h; + int div = radius + radius + 1; + + int r[] = new int[wh]; + int g[] = new int[wh]; + int b[] = new int[wh]; + int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; + int vmin[] = new int[Math.max(w, h)]; + + int divsum = (div + 1) >> 1; + divsum *= divsum; + int dv[] = new int[256 * divsum]; + for (i = 0; i < 256 * divsum; i++) { + dv[i] = (i / divsum); + } + + yw = yi = 0; + + int[][] stack = new int[div][3]; + int stackpointer; + int stackstart; + int[] sir; + int rbs; + int r1 = radius + 1; + int routsum, goutsum, boutsum; + int rinsum, ginsum, binsum; + + for (y = 0; y < h; y++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + for (i = -radius; i <= radius; i++) { + p = pix[yi + Math.min(wm, Math.max(i, 0))]; + sir = stack[i + radius]; + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + rbs = r1 - Math.abs(i); + rsum += sir[0] * rbs; + gsum += sir[1] * rbs; + bsum += sir[2] * rbs; + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + } + stackpointer = radius; + + for (x = 0; x < w; x++) { + + r[yi] = dv[rsum]; + g[yi] = dv[gsum]; + b[yi] = dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (y == 0) { + vmin[x] = Math.min(x + radius + 1, wm); + } + p = pix[yw + vmin[x]]; + + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[(stackpointer) % div]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi++; + } + yw += w; + } + for (x = 0; x < w; x++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + yp = -radius * w; + for (i = -radius; i <= radius; i++) { + yi = Math.max(0, yp) + x; + + sir = stack[i + radius]; + + sir[0] = r[yi]; + sir[1] = g[yi]; + sir[2] = b[yi]; + + rbs = r1 - Math.abs(i); + + rsum += r[yi] * rbs; + gsum += g[yi] * rbs; + bsum += b[yi] * rbs; + + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + + if (i < hm) { + yp += w; + } + } + yi = x; + stackpointer = radius; + for (y = 0; y < h; y++) { + pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (x == 0) { + vmin[y] = Math.min(y + r1, hm) * w; + } + p = x + vmin[y]; + + sir[0] = r[p]; + sir[1] = g[p]; + sir[2] = b[p]; + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[stackpointer]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi += w; + } + } + + bitmap.setPixels(pix, 0, w, 0, 0, w, h); + + image = new BitmapDrawable(context.getResources(), bitmap); + + } + return image; + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolMaths.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolMaths.java new file mode 100644 index 0000000..f22fbfd --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolMaths.java @@ -0,0 +1,32 @@ +package com.bytecat.algui.AlguiTools; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/27 00:43 + * @Describe Algui数学 + */ +import com.bytecat.algui.AlguiHacker.Vector2; +import com.bytecat.algui.AlguiHacker.Vector3; + +public class AlguiToolMaths { + + public static final String TAG = "AlguiToolMaths"; + + //世界3d坐标到相对4x4矩阵的3d坐标 参数:3d坐标,4x4矩阵阵列,屏幕分辨率 + public static Vector3 worldV3To4x4V3(Vector3 v3, float[] matrixArray, float px, float py) { + Vector3 v23=new Vector3(); + if (v3 != null && matrixArray.length >= 4 * 4) { + //计算屏幕中心点 + float pxMidpoint=px / 2; + float pyMidpoint=py / 2; + v23.z = matrixArray[3] * v3.x + matrixArray[7] * v3.z + matrixArray[11] * v3.y + matrixArray[15]; + if (v23.z == 0) v23.z = 1; //防止除零异常 + v23.x = pxMidpoint + (matrixArray[0] * v3.x + matrixArray[4] * v3.z + matrixArray[8] * v3.y + matrixArray[12]) / v23.z * pxMidpoint; + v23.y = pyMidpoint - (matrixArray[1] * v3.x + matrixArray[5] * v3.z + matrixArray[9] * v3.y + matrixArray[13]) / v23.z * pyMidpoint; + + } + return v23; + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolNative.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolNative.java new file mode 100644 index 0000000..13a9e9c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolNative.java @@ -0,0 +1,50 @@ +package com.bytecat.algui.AlguiTools; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/10/28 09:26 + * @Describe 库工具 + */ + + +import com.bytecat.algui.AlguiManager.AlguiLog; +import java.util.HashSet; +import java.util.Set; + +public class AlguiToolNative { + + public static final String TAG = "AlguiToolNative"; + + private AlguiToolNative() { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + //用来跟踪已加载的库 + private static Set loadedLibraries = new HashSet<>(); + //加载动态库 + public static boolean loadLibrary(String name) { + boolean result = true; + + // 检查库是否已经加载 + if (loadedLibraries.contains(name)) { + AlguiLog.d(TAG,"\""+name + "\"库已经加载,无需重复加载"); + return result; + } + + AlguiLog.d(TAG,"开始加载\""+name+"\"库"); + try { + System.loadLibrary(name); + loadedLibraries.add(name); //记录该库 + AlguiLog.d(TAG,"\""+name + "\"库已加载"); + } catch (UnsatisfiedLinkError e) { + AlguiLog.d(TAG,"\"" + name + "\" 库加载异常:" + e.getMessage()); + e.printStackTrace(); + result = false; + } + + return result; + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolNetwork.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolNetwork.java new file mode 100644 index 0000000..4b5e959 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolNetwork.java @@ -0,0 +1,437 @@ +package com.bytecat.algui.AlguiTools; + + + + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Map; +import com.bytecat.algui.AlguiManager.AlguiLog; +import java.io.UnsupportedEncodingException; +import android.net.Proxy; +import java.security.cert.CertificateFactory; +import java.io.ByteArrayInputStream; +import java.security.cert.X509Certificate; +import java.io.File; +import android.content.Context; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/18 23:41 + * @Describe Algui网络工具 + */ +public class AlguiToolNetwork { + + public static final String TAG = "AlguiToolNetwork"; + + private AlguiToolNetwork() { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + //网络请求回调接口 + public interface NetworkCallback { + void onSuccess(String response);//成功 + void onFailure(String error);//失败 + } + + + public static String get(String url1) { + try { + URL url = new URL(url1); + HttpURLConnection Connection = (HttpURLConnection) url.openConnection(); + Connection.setRequestMethod("GET"); + Connection.setConnectTimeout(3000); + Connection.setReadTimeout(3000); + int responseCode = Connection.getResponseCode(); + if (responseCode == Connection.HTTP_OK) { + InputStream inputStream = Connection.getInputStream(); + ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); + byte[] bytes = new byte[1024]; + int length = 0; + while ((length = inputStream.read(bytes)) != -1) { + arrayOutputStream.write(bytes, 0, length); + arrayOutputStream.flush();//强制释放缓冲区 + } + String s = arrayOutputStream.toString(); + return s; + } else { + return "null"; + } + } catch (Exception e) { + return "null"; + } + } + + + // get请求通用方法 + /*调用示例 + //创建请求头 + Map headers = new HashMap<>(); + headers.put("Accept", "application/json");//返回格式 + //...自定义设置各种请求头属性 + //开始post请求 + NetworkRequestTool.GET("url链接", headers , new NetworkRequestTool.NetworkCallback() { + @Override + public void onSuccess(String response) { + AlguiLog.d("请求成功 网络返回值: " + response); + } + + @Override + public void onFailure(String error) { + AlguiLog.d("请求失败: " + error); + } + }); + */ + public static void GET(final String urlString, final Map headers, final NetworkCallback callback) { + new AsyncTask() { + @Override + protected String doInBackground(Void... voids) { + HttpURLConnection urlConnection = null; // 声明 HttpURLConnection 变量 + try { + // 创建 URL 对象 + URL url = new URL(urlString); + // 打开连接 + urlConnection = (HttpURLConnection) url.openConnection(); + // 设置请求方法为 GET + urlConnection.setRequestMethod("GET"); + + // 设置默认请求头信息 + urlConnection.setRequestProperty("Accept", "application/json"); // 响应返回格式 + + // 如果有其他请求头,则设置它们 + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + urlConnection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + + // 获取响应码 + int responseCode = urlConnection.getResponseCode(); + // 判断响应码是否为200 + if (responseCode == HttpURLConnection.HTTP_OK) { + // 读取响应内容 + BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + StringBuilder response = new StringBuilder(); // 用于存储响应内容 + String line; + // 按行读取响应 + while ((line = in.readLine()) != null) { + response.append(line); // 将每一行追加到响应字符串中 + } + in.close(); // 关闭输入流 + // 请求成功返回获取到的数据 + return response.toString(); + } else { + // 请求失败 + return "error 请求失败,响应码:" + responseCode; + } + } catch (Exception e) { + // 对于异常 + return "error 发生错误 " + e.getMessage(); + } finally { + // 确保连接被断开 + if (urlConnection != null) { + urlConnection.disconnect(); + } + } + } + @Override + protected void onPostExecute(String result) { + if (callback != null) { + if (result.startsWith("error")) { + //包含error则回调失败函数 + callback.onFailure(result); + } else { + //回调成功函数 + callback.onSuccess(result); + } + } + + } + }.execute(); + } + // 重载get,对于无需自定义请求头时 + public static void GET(String urlString, NetworkCallback callback) { + GET(urlString, null, callback); + } + + //Post请求 + public static void POST(final String ur, final String byteString, final NetworkCallback callback) { + new AsyncTask() { + @Override + protected String doInBackground(Void... voids) { + + try { + URL url=new URL(ur); + HttpURLConnection HttpURLConnection=(HttpURLConnection) url.openConnection(); + HttpURLConnection.setReadTimeout(9000); + HttpURLConnection.setRequestMethod("POST"); + OutputStream outputStream = HttpURLConnection.getOutputStream(); + outputStream.write(byteString.getBytes()); + BufferedReader BufferedReader=new BufferedReader(new InputStreamReader(HttpURLConnection.getInputStream())); + String String=""; + StringBuffer StringBuffer=new StringBuffer(); + while ((String = BufferedReader.readLine()) != null) { + StringBuffer.append(String); + } + return StringBuffer.toString(); + } catch (IOException e) { + AlguiLog.e(TAG, "POST请求 异常:" + e.getMessage()); + return "异常:" + e.getMessage(); + } + } + @Override + protected void onPostExecute(String result) { + if (callback != null) { + if (result.startsWith("error")) { + //包含error则回调失败函数 + callback.onFailure(result); + } else { + //回调成功函数 + callback.onSuccess(result); + } + } + + } + }.execute(); + + } + + + //Post请求 + public static String UrlPost(String ur, String byteString) { + String str=""; + try { + URL url=new URL(ur); + HttpURLConnection HttpURLConnection=(HttpURLConnection) url.openConnection(); + HttpURLConnection.setReadTimeout(9000); + HttpURLConnection.setRequestMethod("POST"); + OutputStream outputStream = HttpURLConnection.getOutputStream(); + outputStream.write(byteString.getBytes()); + BufferedReader BufferedReader=new BufferedReader(new InputStreamReader(HttpURLConnection.getInputStream())); + String String=""; + StringBuffer StringBuffer=new StringBuffer(); + while ((String = BufferedReader.readLine()) != null) { + StringBuffer.append(String); + } + str = StringBuffer.toString(); + } catch (IOException e) {} + return str; + } + public static String getSeries(String v, String key) { + String ies="0"; + + if (key == null || key.length() <= 0) { + byte[] bkey = v.getBytes(); + + byte state[] = new byte[256]; + + for (int i = 0; i < 256; i++) { + state[i] = (byte) i; + } + int index1 = 0; + int index2 = 0; + if (bkey.length <= 0) { + ies = "-1"; + } else { + for (int i = 0; i < 256; i++) { + index2 = ((bkey[index1] & 0xff) + (state[i] & 0xff) + index2) & 0xff; + byte tmp = state[i]; + state[i] = state[index2]; + state[index2] = tmp; + index1 = (index1 + 1) % bkey.length; + } + } + } else { + try { + ies = AlguiToolRC4.decryRC4(key, "AlguiWin2FA", "UTF-8"); + } catch (UnsupportedEncodingException e) {} + } + + return ies; + } + + //post请求通用方法 + /*调用示例 + //创建请求头 + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); //传参格式 + headers.put("Accept", "application/json");//返回格式 + //...自定义设置各种请求头属性 + //开始post请求 + NetworkRequestTool.POST("url链接", "character=en-US-AriaNeural&text=yes",headers , new NetworkRequestTool.NetworkCallback() { + @Override + public void onSuccess(String response) { + AlguiLog.d("请求成功 网络返回值: " + response); + } + + @Override + public void onFailure(String error) { + AlguiLog.d("请求失败: " + error); + } + }); + */ + public static void POST(final String urlString, final String jsonInputString, final Map headers, final NetworkCallback callback) { + new AsyncTask() { + @Override + protected String doInBackground(Void... voids) { + HttpURLConnection urlConnection = null; // 声明 HttpURLConnection 变量 + try { + // 创建 URL 对象 + URL url = new URL(urlString); + // 打开连接 + urlConnection = (HttpURLConnection) url.openConnection(); + // 设置请求方法为 POST + urlConnection.setRequestMethod("POST"); + urlConnection.setDoOutput(true); // 允许输出 + + // 设置默认请求头信息 + urlConnection.setRequestProperty("Content-Type", "application/json; utf-8");//请求体传参格式 + urlConnection.setRequestProperty("Accept", "application/json");//响应返回格式 + + // 如果有其他请求头,则设置它们 + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + urlConnection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + + // 发送请求体 + try (OutputStream os = urlConnection.getOutputStream()) { + byte[] input = jsonInputString.getBytes("utf-8"); // 将 JSON 字符串转换为字节数组 + os.write(input, 0, input.length); // 写入请求体 + } + // 获取响应码 + int responseCode = urlConnection.getResponseCode(); + + + // 判断响应码是否为200 + if (responseCode == HttpURLConnection.HTTP_OK) { + // 读取响应内容 + BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + StringBuilder response = new StringBuilder(); // 用于存储响应内容 + String line; + // 按行读取响应 + while ((line = in.readLine()) != null) { + response.append(line); // 将每一行追加到响应字符串中 + } + in.close(); // 关闭输入流 + // 请求成功返回获取到的数据 + return response.toString(); + } else { + // 请求失败 + return "error 请求失败,响应码:" + responseCode; + } + } catch (Exception e) { + // 对于异常 + return "error 发生错误 " + e.getMessage(); + } finally { + // 确保连接被断开 + if (urlConnection != null) { + urlConnection.disconnect(); + } + } + } + @Override + protected void onPostExecute(String result) { + if (callback != null) { + if (result.startsWith("error")) { + //包含error则回调失败函数 + callback.onFailure(result); + } else { + //回调成功函数 + callback.onSuccess(result); + } + } + + } + }.execute(); + } + //重载post 对于无需自定义请求头时 + /* public static void POST(String urlString, String jsonInputString, NetworkCallback callback) { + POST(urlString, jsonInputString, null, callback); + }*/ + + //跳转网站 + public static boolean jumpWebSite(Activity context, String url) { + if (context == null) { + return false; + } + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url != null ?url: "https://cn.bing.com/"))); + return true; + } + + + + + + + //检测是否使用了代理 + public static boolean isUsingProxy() { + String proxyHost = System.getProperty("http.proxyHost"); + if (proxyHost != null && !proxyHost.isEmpty()) { + return true; + } + return Proxy.getDefaultHost() != null; + } + + //SSL证书检测 + public static boolean isCertificatePinned(String certContent) { + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + InputStream certStream = new ByteArrayInputStream(certContent.getBytes()); + X509Certificate cert = (X509Certificate) cf.generateCertificate(certStream); + + return cert.getIssuerDN().equals(cert.getSubjectDN()); //检测自签名证书 + } catch (Exception e) { + return false; + } + } + + + //检测是否存在VPN + public static boolean isVPNActive() { + try { + String vpnService = System.getProperty("vpnservice"); + return vpnService != null && !vpnService.isEmpty(); + } catch (Exception e) { + return false; + } + } + + //检测设备是否安装了某些抓包工具 + public static boolean isFridaDetected() { + String[] fridaPaths = { + "/data/data/com.frida.server", + "/system/bin/frida-server" + }; + for (String path : fridaPaths) { + if (new File(path).exists()) { + return true; + } + } + return false; + } + + //综合 + public static boolean isUnderAttack() { + if (isUsingProxy()) { + return true; + } + if (isVPNActive()) { + return true; + } + return false; + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolPermission.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolPermission.java new file mode 100644 index 0000000..b452017 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolPermission.java @@ -0,0 +1,167 @@ +package com.bytecat.algui.AlguiTools; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.provider.Settings; +import android.Manifest; +import android.app.Activity; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/16 03:39 + * @Describe App权限工具 + */ +public class AlguiToolPermission { + + public static final String TAG = "AlguiToolPermission"; + + + private AlguiToolPermission() { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + //申请权限结果回调接口 + public interface PermissionCallback { void run(boolean consequence); } + + //申请权限 + public static void getPermission(Activity a, String permission) { + if (a.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) + a.requestPermissions(new String[]{permission}, 1); + } + + //申请权限并在允许后回调 + public static void getPermission(final Activity a, final String permission, final PermissionCallback call) { + if (a.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { + a.requestPermissions(new String[]{permission}, 1); + + + final Handler handler = new Handler(); + final Runnable checkPermissionRunnable = new Runnable() { + int max=20;//超时时间(秒) + int m;//计时 + @Override + public void run() { + if (a.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) { + if (call != null) { + call.run(true); + } + handler.removeCallbacks(this); + return; + } else { + //超时则未授予 + if(m>=max){ + if (call != null) { + call.run(false); + } + handler.removeCallbacks(this); + return; + } + handler.postDelayed(this, 1000); //每秒检查一次 + m++; + } + } + }; + handler.post(checkPermissionRunnable); + } else { + if (call != null) { + call.run(true); + } + } + + } + + //申请悬浮窗权限 + public static void getWindow(Context mContext) { + if (mContext == null) { + return; + } + + if (!(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(mContext))) { + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + mContext.getPackageName())); + mContext.startActivity(intent); + } + return; + } + + //申请悬浮窗权限 并监听允许了权限才回调 + public static void getWindow(final Context mContext, final PermissionCallback call) { + getWindow(mContext);//申请悬浮窗权限 + //开始监听是否授予了悬浮窗权限 + + final Handler handler = new Handler(); + final Runnable checkPermissionRunnable = new Runnable() { + int max=20;//超时时间(秒) + int m;//计时 + @Override + public void run() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(mContext)) { + if (call != null) { + call.run(true); + } + handler.removeCallbacks(this); + return; + } else { + //超时则未授予 + if(m>=max){ + if (call != null) { + call.run(false); + } + handler.removeCallbacks(this); + return; + } + handler.postDelayed(this, 1000); //每秒检查一次 + m++; + } + } + }; + handler.post(checkPermissionRunnable); + } +//申请存储 + + public static void initSave(Activity ac) { + boolean isGranted = true; + if (Build.VERSION.SDK_INT >= 23) { + if (ac.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) { + isGranted = false; + } + if (ac.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) { + isGranted = false; + } + if (!isGranted) { + ac.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 102); + } + } + } + + + + //检查当前应用程序AndroidManifest.xml安卓清单文件中 是否存在某个权限 分别传入上下文和权限代号 + //实例: + /*if (AppUtilsTool.isAndroidManifestAuthority(context, "android.permission.SYSTEM_ALERT_WINDOW")) { + Log.d("艾琳debug","清单文件中存在悬浮窗权限"); + }else{ + Log.d("艾琳debug","清单文件中不存在悬浮窗权限"); + }*/ + public static boolean isAndroidManifestPermissionExist(Context context, String Authority) { + String permission = Authority; + try { + PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS); + String[] permissions = packageInfo.requestedPermissions; + if (permissions != null) { + for (String p : permissions) { + if (p.equals(permission)) { + return true; + } + } + } + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return false; + } +} + diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolProcess.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolProcess.java new file mode 100644 index 0000000..4eb97e0 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolProcess.java @@ -0,0 +1,116 @@ +package com.bytecat.algui.AlguiTools; +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2025/01/03 07:50 + * @Describe Algui进程工具 + */ +public class AlguiToolProcess { + + public static final String TAG = "AlguiToolProcess"; + + + // 获取所有进程的信息,并格式化为应用名称[PID] 包名的字符串数组 + public static String[] getAllProcesses(Context context) { + List processList = new ArrayList<>(); + + // 使用 ActivityManager 获取当前正在运行的应用信息 + ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List runningAppProcesses = activityManager.getRunningAppProcesses(); + + if (runningAppProcesses != null) { + for (ActivityManager.RunningAppProcessInfo processInfo : runningAppProcesses) { + String packageName = processInfo.processName; + int pid = processInfo.pid; + + // 获取应用名称 + String appName = getAppNameFromPackage(context, packageName); + + // 格式化信息并添加到列表中 + String processInfoString = appName + "[" + pid + "] " + packageName; + processList.add(processInfoString); + } + } + + // 如果有权限,可以通过 ps 命令获取更多进程信息 + processList.addAll(getProcessesFromPsCommand()); + + // 返回格式化后的进程信息数组 + return processList.toArray(new String[0]); + } + + // 使用 ps 命令获取所有进程信息,并格式化 + private static List getProcessesFromPsCommand() { + List processList = new ArrayList<>(); + try { + // 通过 ps 命令获取所有进程信息 + String[] cmd = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + ? new String[]{"/system/bin/ps", "-A"} + : new String[]{"/system/bin/ps"}; + + Process process = Runtime.getRuntime().exec(cmd); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line; + while ((line = reader.readLine()) != null) { + // 解析每行进程信息 + String formattedProcessInfo = parseProcessInfo(line); + if (formattedProcessInfo != null) { + processList.add(formattedProcessInfo); + } + } + process.waitFor(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + return processList; + } + + // 解析 ps 命令返回的进程信息 + private static String parseProcessInfo(String line) { + String[] tokens = line.split("\\s+"); + if (tokens.length > 8) { + String pid = tokens[1]; + String packageName = tokens[8]; + + // 根据进程名获取应用名称 + String appName = getAppNameFromPackageName(packageName); + if (appName != null) { + return appName + "[" + pid + "] " + packageName; + } + } + return null; + } + + // 获取包名对应的应用名称 + private static String getAppNameFromPackage(Context context, String packageName) { + try { + return context.getPackageManager().getApplicationLabel( + context.getPackageManager().getApplicationInfo(packageName, 0)).toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return "Unknown"; + } + + // 根据包名获取应用名称(简单实现) + private static String getAppNameFromPackageName(String packageName) { + try { + // 这里简单地返回包名的后缀作为应用名称 + return packageName.substring(packageName.lastIndexOf('.') + 1); + } catch (Exception e) { + return "Unknown"; + } + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolRC4.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolRC4.java new file mode 100644 index 0000000..86ff6f5 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolRC4.java @@ -0,0 +1,162 @@ +package com.bytecat.algui.AlguiTools; +import java.io.UnsupportedEncodingException; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/18 03:39 + * @Describe rc4加解密 + */ +public class AlguiToolRC4 { + /** + * RC4加密,将加密后的数据进行哈希 + * + * @param data 需要加密的数据 + * @param key 加密密钥 + * @param chartSet 编码方式 + * @return 返回加密后的数据 + * @throws UnsupportedEncodingException + */ + public static String encryRC4String(String data, String key, String chartSet) throws UnsupportedEncodingException { + if (data == null || key == null) { + return null; + } + return bytesToHex(encryRC4Byte(data, key, chartSet)); + } + + /** + * RC4加密,将加密后的字节数据 + * + * @param data 需要加密的数据 + * @param key 加密密钥 + * @param chartSet 编码方式 + * @return 返回加密后的数据 + * @throws UnsupportedEncodingException + */ + public static byte[] encryRC4Byte(String data, String key, String chartSet) throws UnsupportedEncodingException { + if (data == null || key == null) { + return null; + } + if (chartSet == null || chartSet.isEmpty()) { + byte bData[] = data.getBytes(); + return RC4Base(bData, key); + } else { + byte bData[] = data.getBytes(chartSet); + return RC4Base(bData, key); + } + } + + /** + * RC4解密 + * + * @param data 需要解密的数据 + * @param key 加密密钥 + * @param chartSet 编码方式 + * @return 返回解密后的数据 + * @throws UnsupportedEncodingException + */ + public static String decryRC4(String data, String key, String chartSet) throws UnsupportedEncodingException { + if (data == null || key == null) { + return null; + } + return new String(RC4Base(hexToByte(data), key), chartSet); + } + + /** + * RC4加密初始化密钥 + * + * @param aKey + * @return + */ + private static byte[] initKey(String aKey) { + byte[] bkey = aKey.getBytes(); + byte state[] = new byte[256]; + + for (int i = 0; i < 256; i++) { + state[i] = (byte) i; + } + int index1 = 0; + int index2 = 0; + if (bkey.length == 0) { + return null; + } + for (int i = 0; i < 256; i++) { + index2 = ((bkey[index1] & 0xff) + (state[i] & 0xff) + index2) & 0xff; + byte tmp = state[i]; + state[i] = state[index2]; + state[index2] = tmp; + index1 = (index1 + 1) % bkey.length; + } + return state; + } + + + /** + * 字节数组转十六进制 + * + * @param bytes + * @return + */ + public static String bytesToHex(byte[] bytes) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + String hex = Integer.toHexString(bytes[i] & 0xFF); + if (hex.length() < 2) { + sb.append(0); + } + sb.append(hex); + } + return sb.toString(); + } + + /** + * 十六进制转字节数组 + * + * @param inHex + * @return + */ + public static byte[] hexToByte(String inHex) { + int hexlen = inHex.length(); + byte[] result; + if (hexlen % 2 == 1) { + hexlen++; + result = new byte[(hexlen / 2)]; + inHex = "0" + inHex; + } else { + result = new byte[(hexlen / 2)]; + } + int j = 0; + for (int i = 0; i < hexlen; i += 2) { + result[j] = (byte) Integer.parseInt(inHex.substring(i, i + 2), 16); + j++; + } + return result; + } + + /** + * RC4解密 + * + * @param input + * @param mKkey + * @return + */ + private static byte[] RC4Base(byte[] input, String mKkey) { + int x = 0; + int y = 0; + byte key[] = initKey(mKkey); + int xorIndex; + byte[] result = new byte[input.length]; + for (int i = 0; i < input.length; i++) { + x = (x + 1) & 0xff; + y = ((key[x] & 0xff) + y) & 0xff; + byte tmp = key[x]; + key[x] = key[y]; + key[y] = tmp; + xorIndex = ((key[x] & 0xff) + (key[y] & 0xff)) & 0xff; + result[i] = (byte) (input[i] ^ key[xorIndex]); + } + return result; + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolView.java b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolView.java new file mode 100644 index 0000000..5eab1ec --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiTools/AlguiToolView.java @@ -0,0 +1,155 @@ +package com.bytecat.algui.AlguiTools; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.util.TypedValue; +import android.content.res.Resources; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/16 01:25 + * @Describe 视图工具 + */ +public class AlguiToolView { + + public static final String TAG = "AlguiToolView"; + + private AlguiToolView() + { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public static float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + /** + * 根据手机的分辨率从 px(像素) 的单位 转成为 dp + */ + public static int px2dp(Context context, float pxValue) { + if(context==null){ + return (int)pxValue; + } + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + //让颜色更有层次感的工具 + public static int createLayeredColor(int baseColor, float alphaFactor) { + // 提取RGB分量和透明度 + int red = Color.red(baseColor); + int green = Color.green(baseColor); + int blue = Color.blue(baseColor); + int alpha = Color.alpha(baseColor); + + // 计算新的透明度 + int newAlpha = (int) (alpha * alphaFactor); + + // 创建新的颜色并返回 + return Color.argb(newAlpha, red, green, blue); + } + + //计算颜色的反色的工具 比如白色的反色是黑色 参数:颜色 + public static int calculateColorInverse(int color) { + int red = 255 - Color.red(color); + int green = 255 - Color.green(color); + int blue = 255 - Color.blue(color); + + return Color.rgb(red, green, blue); + } + + //颜色加深工具 参数:颜色 加深比例0-1 + static public int darkenColor(int color, float ratio) { + // 获取原始颜色的ARGB分量 + int alpha = Color.alpha(color); + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + + // 对红、绿、蓝三个分量进行加深处理 + red = (int) (red * ratio); + green = (int) (green * ratio); + blue = (int) (blue * ratio); + + // 修正分量值超出范围的情况 + red = Math.min(red, 255); + green = Math.min(green, 255); + blue = Math.min(blue, 255); + + // 合成新的颜色值 + return Color.argb(alpha, red, green, blue); + } + + + //颜色变亮工具 + public static int brightenColor(int color) { + float[] hsv = new float[3]; + Color.colorToHSV(color, hsv); + hsv[1] = hsv[1] * 1.2f; // 饱和度增加20% + hsv[2] = hsv[2] * 1.2f; // 明度增加20% + return Color.HSVToColor(hsv); + } + + + //设置文本视图阴影 参数:文本视图,阴影半径,阴影水平偏移量,阴影垂直偏移量,阴影颜色 + public static TextView setTextViewShadow(TextView textView, float radius, float xOffset, float yOffset, int shadowColor) { + if (textView == null) { + return textView; + } + textView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); // 开启软件加速,以支持setShadowLayer() + textView.setShadowLayer(radius, xOffset, yOffset, shadowColor); //设置文本阴影 接受四个参数:阴影的模糊半径、阴影的水平偏移量、阴影的垂直偏移量和阴影的颜色 + return textView; + } + + //设置视图渐变背景 参数:视图对象,渐变颜色数组,渐变类型 + public static Drawable setGradientBackground(ViewGroup view, int[] colors,int gradientType) { + if(view==null||colors==null){ + return null; + } + + Drawable b = view.getBackground(); + + if (b == null) { + GradientDrawable back=new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors); + // 设置渐变类型 + back.setGradientType(gradientType); + view.setBackground(back); + return back; + } else { + if (b instanceof GradientDrawable) { + GradientDrawable gd=(GradientDrawable)b; + //设置渐变方向为 从左到右 + gd.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); + //设置渐变颜色数组 + gd.setColors(colors); + // 设置渐变类型为线性渐变 + gd.setGradientType(gradientType); + return gd; + } + } + return b; + + } + + + //判断是否为渐变类型 + public static boolean isGdType(int typeIndex) { + return typeIndex == GradientDrawable.LINE || + typeIndex == GradientDrawable.LINEAR_GRADIENT || + typeIndex == GradientDrawable.OVAL || + typeIndex == GradientDrawable.RADIAL_GRADIENT || + typeIndex == GradientDrawable.RECTANGLE || + typeIndex == GradientDrawable.RING || + typeIndex == GradientDrawable.SWEEP_GRADIENT; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiFlowLayout.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiFlowLayout.java new file mode 100644 index 0000000..263ffc6 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiFlowLayout.java @@ -0,0 +1,470 @@ +package com.bytecat.algui.AlguiViews; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/11/08 20:28 + * @Describe Algui流式布局 添加视图时默认横向从左到右依次添加,调用endl代表当前行已结束需换行添加 + */ +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.graphics.drawable.GradientDrawable; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import java.util.ArrayList; +import java.util.Arrays; + +public class AlguiFlowLayout extends LinearLayout { + + public static final String TAG = "AlguiFlowLayout"; + Context context; + + LinearLayout.LayoutParams params;//布局参数 + GradientDrawable mainBackground;//背景 + ArrayList lineList = new ArrayList<>();//所有行 + + //样式 + float sWidth, sHeight; // 宽高 + float sWeight; // 权重 + float[] sPadding, sMargins; // 内边距和外边距 + int[] sBackColors; // 背景颜色 + float sStrokeSize = -1; // 描边大小 + int sStrokeColor = -1; // 描边颜色 + float sFilletRadiu = -1; // 圆角半径 + int sOrientation;//方向 + float[] allLineMargins=new float[]{0,0,0,0};//所有行的外边距 + + public float getByteStyleWidth() { return sWidth; } // 获取宽度 + public float getByteStyleHeight() { return sHeight; } // 获取高度 + public float getByteStyleWeight() { return sWeight; } // 获取权重 + public float[] getByteStylePadding() { return sPadding; } // 获取内边距 + public float[] getByteStyleMargins() { return sMargins; } // 获取外边距 + public int[] getByteStyleBackColors() { return sBackColors; } // 获取背景颜色 + public float getByteStyleBorderSize() { return sStrokeSize; } // 获取描边大小 + public int getByteStyleBorderColor() { return sStrokeColor; } // 获取描边颜色 + public float getByteStyleRadius() { return sFilletRadiu; } // 获取圆角半径 + public float getByteStyleOrientation() { return isVertical ?VERTICAL: HORIZONTAL; } // 获取方向 + public float[] getByteLineMargins() { return allLineMargins; } // 获取所有行外边距 + + //拓展方法 + public LinearLayout.LayoutParams getByteParams() { return params; }//获取布局参数 + public GradientDrawable getByteBack() { return mainBackground; }//获取背景 + public ArrayList getByteLineList() {return lineList;}//获取所有行 + //获取当前行 (最后一行) + public AlguiLinearLayout getByteLine() { + //如果还没有行则创建 + if (lineList.size() <= 0) { + endl(); + } + return getByteLine(lineList.size() - 1); + } + //获取指定行 + public AlguiLinearLayout getByteLine(int index) { + AlguiLinearLayout l=null; + if (index >= 0 && index < lineList.size()) { + l = lineList.get(index); + } + return l; + } + + float + mRadius,//圆角半径 + tBorderSize; //描边大小 + int tBorderColor;//描边颜色 + + int lineMaxView=0;//所有行最大视图数量自动换行 (0则不自动换行需手动换行) + + boolean isVertical;//是否垂直 + public static final int VERTICAL = 0x1;//垂直 + public static final int HORIZONTAL = 0x0;//横向 + + public AlguiFlowLayout(Context context) { + super(context); + this.context = context; + init(); + setCatOrientation(HORIZONTAL);//默认横向 + } + + //初始化父容器 + private void init() { + params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, 1); + setLayoutParams(params); + setClipChildren(true);//子视图超过边界时自动裁剪 + setClipToOutline(true);//根据父视图轮廓裁剪 + mainBackground = new GradientDrawable(); + setBackground(mainBackground); + } + + //设置行的方向 + //(垂直=父容器横向添加行,行垂直添加视图 & 横向=父容器垂直添加行,行横向添加视图) + public AlguiFlowLayout setCatOrientation(int orientation) { + sOrientation = orientation; + switch (orientation) { + default: + case VERTICAL: + isVertical = true; + break; + case HORIZONTAL: + isVertical = false; + break; + } + super.setOrientation(isVertical ?HORIZONTAL: VERTICAL);//设置父容器方向 + return this; + } + + //设置行的最大视图数量 超出则自动换行 + public AlguiFlowLayout setCatLineMaxView(int num) { + lineMaxView = num; + return this; + } + //设置所有行的外边距 + public AlguiFlowLayout setCatLineMargins(float left, float top, float right, float bottom) { + allLineMargins=new float[]{left,top,right,bottom}; + for (AlguiLinearLayout line:lineList) { + if (line != null) { + line.setCatMargins(allLineMargins[0],allLineMargins[1],allLineMargins[2],allLineMargins[3]); + } + } + return this; + } + + + + + //设置父布局 + public AlguiFlowLayout setCatParentLayout(ViewGroup vg) { + if (vg != null) + vg.addView(this); + return this; + } + + //删除所有视图 + public AlguiFlowLayout remAllView() { + //清除所有行 + for (AlguiLinearLayout l : lineList) { + remLine(l); + } + super.removeAllViews();//清除容器内容 + return this; + } + //删除子视图 + public AlguiFlowLayout remView(View... view) { + int i=0; + for (AlguiLinearLayout l:lineList) { + if (l != null) { + for (View v:view) { + if (v != null) { + if (l.indexOfChild(v) != -1) { + l.removeView(v); + i++; + } else if (super.indexOfChild(v) != -1) { + super.removeView(v); + i++; + } + if (i >= view.length) { + return this; + } + } + } + } + + } + return this; + } + //删除指定行的视图 + public AlguiFlowLayout remViewToLine(int index, View... views) { + AlguiLinearLayout l = getByteLine(index); + if (l != null) { + l.remView(views); + } + return this; + } + //删除指定行 (按索引) + public AlguiFlowLayout remLine(int... indexs) { + for (int index:indexs) { + AlguiLinearLayout l = getByteLine(index); + if (l != null) { + remLine(l);//删除 + } + } + return this; + } + //删除指定行 (按对象) + public AlguiFlowLayout remLine(AlguiLinearLayout... objs) { + for (AlguiLinearLayout obj:objs) { + if (obj != null && lineList.contains(obj)) { + obj.remAllView();//删除该行所有子视图 + super.removeView(obj);//从父容器删除 + lineList.remove(obj);//从行列表删除 + obj = null;//回收 + } + } + return this; + } + + //行结束 (换行) + public AlguiLinearLayout endl() { + //创建新的行 + AlguiLinearLayout line = new AlguiLinearLayout(context); + line.setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); + line.setCatWeight(1); + line.setCatMargins(allLineMargins[0], allLineMargins[1], allLineMargins[2], allLineMargins[3]); + line.setOrientation(isVertical ?VERTICAL: HORIZONTAL);//设置方向 + line.setClipToOutline(true);//根据父视图轮廓裁剪 + line.setGravity(isVertical ?Gravity.CENTER_HORIZONTAL: Gravity.CENTER_VERTICAL); + super.addView(line, -1, line.getByteParams());//添加当前行到主容器 + lineList.add(line);//保存当前行到列表 + + return line; + } + //自动换行 + private void aEndl() { + //只有存在一行最大视图数量才自动换行 + if (lineMaxView > 0) { + int num = getByteLine().getChildCount();//获取当前行子视图数量 + //当前数量为一行最大视图数量则自动换行 + if (num >= lineMaxView) { + endl(); + } + } + + } + + //添加视图到指定行 + public AlguiFlowLayout addViewToLine(int index, View... views) { + AlguiLinearLayout l = getByteLine(index); + if (l != null) { + l.addView(views); + } + return this; + } + //重写添加视图的函数 确保新视图添加到末尾行当中而不是根容器 + //在最后一行添加一些视图 中途null代表换行 + public AlguiFlowLayout addView(View... view) { + for (View aView : view) { + if (aView != null) { + aEndl();//自动换行 + AlguiLinearLayout l = getByteLine();//获取最后一行 + if (l.indexOfChild(aView) == -1) + l.addView(aView);//在最后一行添加视图 + } else { + //null代表手动换行 + endl(); + } + } + return this; + } + @Override + public void addView(View child) { + if (child != null) { + aEndl();//自动换行 + AlguiLinearLayout l = getByteLine();//获取最后一行 + if (l.indexOfChild(child) == -1) + l.addView(child);//在最后一行添加视图 + } + + } + @Override + public void addView(View child, int index) { + if (child != null) { + aEndl();//自动换行 + AlguiLinearLayout l = getByteLine();//获取最后一行 + if (l.indexOfChild(child) == -1) + l.addView(child);//在最后一行添加视图 + } + } + @Override + public void addView(View child, int width, int height) { + + if (child != null) { + aEndl();//自动换行 + AlguiLinearLayout l = getByteLine();//获取最后一行 + if (l.indexOfChild(child) == -1) + l.addView(child);//在最后一行添加视图 + } + } + //重写后内部往父类添加视图时必须使用此重载 index直接填-1即可 + //原因:其它重载在父类内部会间接最终调用到这个重载 + // 由于重写了所以父类会调用子类重写的重载 + // 那么往父类添加insideLayout时就会无限递归 所以内部必须使用此重装添加 + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + if (child != null) { + aEndl();//自动换行 + AlguiLinearLayout l = getByteLine();//获取最后一行 + if (l.indexOfChild(child) == -1) + l.addView(child);//在最后一行添加视图 + } + } + @Override + public void addView(View child, ViewGroup.LayoutParams params) { + if (child != null) { + aEndl();//自动换行 + AlguiLinearLayout l = getByteLine();//获取最后一行 + if (l.indexOfChild(child) == -1) + l.addView(child);//在最后一行添加视图 + } + } + + + + + + + + + + + //设置大小 + public AlguiFlowLayout setCatSize(float w, float h) { + sWidth = w; + sHeight = h; + if ((int)w != ViewGroup.LayoutParams.WRAP_CONTENT + && (int) w != ViewGroup.LayoutParams.MATCH_PARENT + && (int)w != ViewGroup.LayoutParams.FILL_PARENT) { + params.width = (int)dp2px(w); + } else { + params.width = (int)w; + } + + if ((int)h != ViewGroup.LayoutParams.WRAP_CONTENT + && (int)h != ViewGroup.LayoutParams.MATCH_PARENT + && (int)h != ViewGroup.LayoutParams.FILL_PARENT) { + params.height = (int)dp2px(h); + } else { + params.height = (int)h; + } + requestLayout();//重新计算布局 + return this; + } + + //设置权重 + public AlguiFlowLayout setCatWeight(float weight) { + sWeight = weight; + params.weight = weight; + requestLayout();//重新计算布局 + return this; + } + + //设置内边距 + public AlguiFlowLayout setCatPadding(float left, float top, float right, float bottom) { + sPadding = new float[]{left,top,right,bottom}; + setPadding( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + + //设置外边距 + public AlguiFlowLayout setCatMargins(float left, float top, float right, float bottom) { + sMargins = new float[]{left,top,right,bottom}; + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + //设置背景颜色 + public AlguiFlowLayout setCatBackColor(int... backColor) { + sBackColors = backColor; + if (backColor.length == 1) { + //单个颜色 + mainBackground.setColor(backColor[0]); + } else if (backColor.length > 1) { + //多个颜色,使用渐变 + mainBackground.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); //渐变方向 + //最后一个元素如果是渐变类型则应用否则默认线性渐变 + if (isGdType(backColor[backColor.length - 1])) { + mainBackground.setGradientType(backColor[backColor.length - 1]); + int[] newArray = Arrays.copyOf(backColor, backColor.length - 1);//删除最后一个元素 + mainBackground.setColors(newArray);//设置颜色 + } else { + mainBackground.setGradientType(GradientDrawable.LINEAR_GRADIENT); + mainBackground.setColors(backColor);//设置颜色 + } + } + + return this; + } + + + //设置圆角半径 + public AlguiFlowLayout setCatRadiu(float radiu) { + sFilletRadiu = radiu; + mRadius = dp2px(radiu); + mainBackground.setCornerRadius(mRadius); + invalidate(); + return this; + } + + //设置描边 + public AlguiFlowLayout setCatBorder(float borderSize, int borderColor) { + sStrokeSize = borderSize; + sStrokeColor = borderColor; + //先设置内边距防止描边过大时覆盖子视图 + float bs = dp2px(borderSize);//新的描边 + int w=(int)((bs - tBorderSize) / 2);//计算内边距差值 + this.setPadding(getPaddingLeft() + w, getPaddingTop() + w, getPaddingRight() + w, getPaddingBottom() + w); + //应用 + tBorderSize = bs; + tBorderColor = borderColor; + invalidate(); + return this; + } + + + //绘制子视图 + //这里使其描边沿圆角进行描边 + @Override + protected void dispatchDraw(Canvas canvas) { + int width=getWidth(); + int height=getHeight(); + //先规划圆角轮廓路径 + Path path = new Path();//存储圆角路径 + RectF rectF = new RectF(); + rectF.set(0, 0, width, height); + path.addRoundRect(rectF, mRadius, mRadius, Path.Direction.CW); + + //保存当前画布状态 + int saveCount = canvas.save(); + canvas.clipPath(path);//裁剪子布局超出圆角的部分 + super.dispatchDraw(canvas); //然后绘制子视图 + + //开始绘制描边 + Paint borderPaint = new Paint(); + borderPaint.setColor(tBorderColor); //设置描边颜色 + borderPaint.setStyle(Paint.Style.STROKE); + borderPaint.setStrokeWidth(tBorderSize); //设置描边宽度 + canvas.drawPath(path, borderPaint);//沿圆角路径绘制描边 + //恢复画布状态 + canvas.restoreToCount(saveCount); + } + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + //判断是否为渐变类型 + public boolean isGdType(int typeIndex) { + return typeIndex == GradientDrawable.LINE || + typeIndex == GradientDrawable.LINEAR_GRADIENT || + typeIndex == GradientDrawable.OVAL || + typeIndex == GradientDrawable.RADIAL_GRADIENT || + typeIndex == GradientDrawable.RECTANGLE || + typeIndex == GradientDrawable.RING || + typeIndex == GradientDrawable.SWEEP_GRADIENT; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiFrameLayout.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiFrameLayout.java new file mode 100644 index 0000000..3f00cff --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiFrameLayout.java @@ -0,0 +1,267 @@ +package com.bytecat.algui.AlguiViews; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.graphics.drawable.GradientDrawable; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import java.util.Arrays; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/16 01:25 + * @Describe Algui框架布局 + */ +public class AlguiFrameLayout extends FrameLayout { + public static final String TAG = "AlguiFrameLayout"; + + Context context; + LinearLayout.LayoutParams params;//布局参数 + GradientDrawable mainBackground;//背景 + float + mRadius,//圆角半径 + tBorderSize; //描边大小 + int tBorderColor;//描边颜色 + + //样式 + float sWidth, sHeight; // 宽高 + float sWeight; // 权重 + float[] sPadding, sMargins; // 内边距和外边距 + int[] sBackColors; // 背景颜色 + float sStrokeSize = -1; // 描边大小 + int sStrokeColor = -1; // 描边颜色 + float sFilletRadiu = -1; // 圆角半径 + + public float getByteStyleWidth() { return sWidth; } // 获取宽度 + public float getByteStyleHeight() { return sHeight; } // 获取高度 + public float getByteStyleWeight() { return sWeight; } // 获取权重 + public float[] getByteStylePadding() { return sPadding; } // 获取内边距 + public float[] getByteStyleMargins() { return sMargins; } // 获取外边距 + public int[] getByteStyleBackColors() { return sBackColors; } // 获取背景颜色 + public float getByteStyleBorderSize() { return sStrokeSize; } // 获取描边大小 + public int getByteStyleBorderColor() { return sStrokeColor; } // 获取描边颜色 + public float getByteStyleRadius() { return sFilletRadiu; } // 获取圆角半径 + + + /** + * 获取布局参数 + * + * @return LinearLayout.LayoutParams 返回当前的布局参数 + */ + public LinearLayout.LayoutParams getByteParams() { + return params; + } + /** + * 获取背景 + * + * @return GradientDrawable 返回当前的背景Drawable + */ + public GradientDrawable getByteBack() { + return mainBackground; + } + + + public AlguiFrameLayout(Context context) { + super(context); + this.context = context; + init(); + } + + private void init() { + params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + setLayoutParams(params); + setClipChildren(true);//子视图超过边界时自动裁剪 + setClipToOutline(true);//根据父视图轮廓裁剪 + mainBackground = new GradientDrawable(); + setBackground(mainBackground); + + } + + //设置大小 + public AlguiFrameLayout setCatSize(float w, float h) { + sWidth=w; + sHeight=h; + if ((int)w != ViewGroup.LayoutParams.WRAP_CONTENT + && (int) w != ViewGroup.LayoutParams.MATCH_PARENT + && (int)w != ViewGroup.LayoutParams.FILL_PARENT) { + params.width = (int)dp2px(w); + } else { + params.width = (int)w; + } + + if ((int)h != ViewGroup.LayoutParams.WRAP_CONTENT + && (int)h != ViewGroup.LayoutParams.MATCH_PARENT + && (int)h != ViewGroup.LayoutParams.FILL_PARENT) { + params.height = (int)dp2px(h); + } else { + params.height = (int)h; + } + requestLayout();//重新计算布局 + return this; + } + + //设置权重 + public AlguiFrameLayout setCatWeight(float weight) { + sWeight=weight; + params.weight = weight; + requestLayout();//重新计算布局 + return this; + } + + //设置内边距 + public AlguiFrameLayout setCatPadding(float left, float top, float right, float bottom) { + sPadding = new float[]{left,top,right,bottom}; + setPadding( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + + //设置外边距 + public AlguiFrameLayout setCatMargins(float left, float top, float right, float bottom) { + sMargins = new float[]{left,top,right,bottom}; + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + //设置背景颜色 + public AlguiFrameLayout setCatBackColor(int... backColor) { + sBackColors=backColor; + if (backColor.length == 1) { + //单个颜色 + mainBackground.setColor(backColor[0]); + } else if (backColor.length > 1) { + //多个颜色,使用渐变 + mainBackground.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); //渐变方向 + //最后一个元素如果是渐变类型则应用否则默认线性渐变 + if (isGdType(backColor[backColor.length - 1])) { + mainBackground.setGradientType(backColor[backColor.length - 1]); + int[] newArray = Arrays.copyOf(backColor, backColor.length - 1);//删除最后一个元素 + mainBackground.setColors(newArray);//设置颜色 + } else { + mainBackground.setGradientType(GradientDrawable.LINEAR_GRADIENT); + mainBackground.setColors(backColor);//设置颜色 + } + } + + return this; + } + + + //设置圆角半径 + public AlguiFrameLayout setCatRadiu(float radiu) { + sFilletRadiu=radiu; + mRadius = dp2px(radiu); + mainBackground.setCornerRadius(mRadius); + invalidate(); + return this; + } + + //设置描边 + public AlguiFrameLayout setCatBorder(float borderSize, int borderColor) { + sStrokeSize=borderSize; + sStrokeColor=borderColor; + //先设置内边距防止描边过大时覆盖子视图 + float bs = dp2px(borderSize);//新的描边 + int w=(int)((bs - tBorderSize) / 2);//计算内边距差值 + this.setPadding(getPaddingLeft() + w, getPaddingTop() + w, getPaddingRight() + w, getPaddingBottom() + w); + //应用 + tBorderSize = bs; + tBorderColor = borderColor; + invalidate(); + return this; + } + + //设置父布局 + public AlguiFrameLayout setCatParentLayout(ViewGroup vg) { + if (vg != null) + vg.addView(this); + return this; + } + + //添加视图 (仿Xml) + public AlguiFrameLayout addView(View... view) { + for (View aView : view) { + if (aView != null) { + if (super.indexOfChild(aView) == -1) + addView(aView); + } + } + return this; + } + + //删除子视图 + public AlguiFrameLayout remView(View... view) { + for (View aView : view) { + if (aView != null) { + if (super.indexOfChild(aView) != -1) + removeView(aView); + } + } + return this; + } + + //删除所有子视图 + public AlguiFrameLayout remAllView() { + removeAllViews(); + return this; + } + + //绘制子视图 + //这里使其描边沿圆角进行描边 + @Override + protected void dispatchDraw(Canvas canvas) { + int width=getWidth(); + int height=getHeight(); + //先规划圆角轮廓路径 + Path path = new Path();//存储圆角路径 + RectF rectF = new RectF(); + rectF.set(0, 0, width, height); + path.addRoundRect(rectF, mRadius, mRadius, Path.Direction.CW); + + //保存当前画布状态 + int saveCount = canvas.save(); + canvas.clipPath(path);//裁剪子布局超出圆角的部分 + super.dispatchDraw(canvas); //然后绘制子视图 + + //开始绘制描边 + Paint borderPaint = new Paint(); + borderPaint.setColor(tBorderColor); //设置描边颜色 + borderPaint.setStyle(Paint.Style.STROKE); + borderPaint.setStrokeWidth(tBorderSize); //设置描边宽度 + canvas.drawPath(path, borderPaint);//沿圆角路径绘制描边 + //恢复画布状态 + canvas.restoreToCount(saveCount); + } + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + //判断是否为渐变类型 + public boolean isGdType(int typeIndex) { + return typeIndex == GradientDrawable.LINE || + typeIndex == GradientDrawable.LINEAR_GRADIENT || + typeIndex == GradientDrawable.OVAL || + typeIndex == GradientDrawable.RADIAL_GRADIENT || + typeIndex == GradientDrawable.RECTANGLE || + typeIndex == GradientDrawable.RING || + typeIndex == GradientDrawable.SWEEP_GRADIENT; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiLinearLayout.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiLinearLayout.java new file mode 100644 index 0000000..62207e7 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiLinearLayout.java @@ -0,0 +1,273 @@ +package com.bytecat.algui.AlguiViews; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.graphics.drawable.GradientDrawable; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import java.util.Arrays; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/16 01:25 + * @Describe Algui线性布局 + */ +public class AlguiLinearLayout extends LinearLayout { + + public static final String TAG = "AlguiLinearLayout"; + + Context context; + LinearLayout.LayoutParams params;//布局参数 + GradientDrawable mainBackground;//背景 + + float + mRadius,//圆角半径 + tBorderSize; //描边大小 + int tBorderColor;//描边颜色 + + //样式 + float sWidth, sHeight; // 宽高 + float sWeight; // 权重 + float[] sPadding, sMargins; // 内边距和外边距 + int[] sBackColors; // 背景颜色 + float sStrokeSize = -1; // 描边大小 + int sStrokeColor = -1; // 描边颜色 + float sFilletRadiu = -1; // 圆角半径 + + public float getByteStyleWidth() { return sWidth; } // 获取宽度 + public float getByteStyleHeight() { return sHeight; } // 获取高度 + public float getByteStyleWeight() { return sWeight; } // 获取权重 + public float[] getByteStylePadding() { return sPadding; } // 获取内边距 + public float[] getByteStyleMargins() { return sMargins; } // 获取外边距 + public int[] getByteStyleBackColors() { return sBackColors; } // 获取背景颜色 + public float getByteStyleBorderSize() { return sStrokeSize; } // 获取描边大小 + public int getByteStyleBorderColor() { return sStrokeColor; } // 获取描边颜色 + public float getByteStyleRadius() { return sFilletRadiu; } // 获取圆角半径 + + /** + * 获取布局参数 + * + * @return LinearLayout.LayoutParams 返回当前的布局参数 + */ + public LinearLayout.LayoutParams getByteParams() { + return params; + } + + + + /** + * 获取背景 + * + * @return GradientDrawable 返回当前的背景Drawable + */ + public GradientDrawable getByteBack() { + return mainBackground; + } + + + + public AlguiLinearLayout(Context context) { + super(context); + this.context = context; + init(); + } + + private void init() { + params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + setLayoutParams(params); + setClipChildren(true);//子视图超过边界时自动裁剪 + setClipToOutline(true);//根据父视图轮廓裁剪 + mainBackground = new GradientDrawable(); + setBackground(mainBackground); + + } + + //设置大小 + public AlguiLinearLayout setCatSize(float w, float h) { + sWidth=w; + sHeight=h; + if ((int)w != ViewGroup.LayoutParams.WRAP_CONTENT + && (int) w != ViewGroup.LayoutParams.MATCH_PARENT + && (int)w != ViewGroup.LayoutParams.FILL_PARENT) { + params.width = (int)dp2px(w); + } else { + params.width = (int)w; + } + + if ((int)h != ViewGroup.LayoutParams.WRAP_CONTENT + && (int)h != ViewGroup.LayoutParams.MATCH_PARENT + && (int)h != ViewGroup.LayoutParams.FILL_PARENT) { + params.height = (int)dp2px(h); + } else { + params.height = (int)h; + } + requestLayout();//重新计算布局 + return this; + } + + //设置权重 + public AlguiLinearLayout setCatWeight(float weight) { + sWeight=weight; + params.weight = weight; + requestLayout();//重新计算布局 + return this; + } + + //设置内边距 + public AlguiLinearLayout setCatPadding(float left, float top, float right, float bottom) { + sPadding = new float[]{left,top,right,bottom}; + setPadding( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + + //设置外边距 + public AlguiLinearLayout setCatMargins(float left, float top, float right, float bottom) { + sMargins = new float[]{left,top,right,bottom}; + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + //设置背景颜色 + public AlguiLinearLayout setCatBackColor(int... backColor) { + sBackColors=backColor; + if (backColor.length == 1) { + //单个颜色 + mainBackground.setColor(backColor[0]); + } else if (backColor.length > 1) { + //多个颜色,使用渐变 + mainBackground.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); //渐变方向 + //最后一个元素如果是渐变类型则应用否则默认线性渐变 + if (isGdType(backColor[backColor.length - 1])) { + mainBackground.setGradientType(backColor[backColor.length - 1]); + int[] newArray = Arrays.copyOf(backColor, backColor.length - 1);//删除最后一个元素 + mainBackground.setColors(newArray);//设置颜色 + } else { + mainBackground.setGradientType(GradientDrawable.LINEAR_GRADIENT); + mainBackground.setColors(backColor);//设置颜色 + } + } + + return this; + } + + + //设置圆角半径 + public AlguiLinearLayout setCatRadiu(float radiu) { + sFilletRadiu=radiu; + mRadius = dp2px(radiu); + mainBackground.setCornerRadius(mRadius); + invalidate(); + return this; + } + + //设置描边 + public AlguiLinearLayout setCatBorder(float borderSize, int borderColor) { + sStrokeSize=borderSize; + sStrokeColor=borderColor; + //先设置内边距防止描边过大时覆盖子视图 + float bs = dp2px(borderSize);//新的描边 + int w=(int)((bs - tBorderSize) / 2);//计算内边距差值 + this.setPadding(getPaddingLeft() + w, getPaddingTop() + w, getPaddingRight() + w, getPaddingBottom() + w); + //应用 + tBorderSize = bs; + tBorderColor = borderColor; + invalidate(); + return this; + } + + + + + //设置父布局 + public AlguiLinearLayout setCatParentLayout(ViewGroup vg) { + if (vg != null) + vg.addView(this); + return this; + } + + //添加子视图 (仿Xml) + public AlguiLinearLayout addView(View... view) { + for (View aView : view) { + if (aView != null) { + if (super.indexOfChild(aView) == -1) + addView(aView); + } + } + return this; + } + + //删除子视图 + public AlguiLinearLayout remView(View... view) { + for (View aView : view) { + if (aView != null) { + if (super.indexOfChild(aView) != -1) + removeView(aView); + } + } + return this; + } + + //删除所有子视图 + public AlguiLinearLayout remAllView() { + removeAllViews(); + return this; + } + + //绘制子视图 + //这里使其描边能够沿圆角进行描边 + @Override + protected void dispatchDraw(Canvas canvas) { + int width=getWidth(); + int height=getHeight(); + //先规划圆角轮廓路径 + Path path = new Path();//存储圆角路径 + RectF rectF = new RectF(); + rectF.set(0, 0, width, height); + path.addRoundRect(rectF, mRadius, mRadius, Path.Direction.CW); + + //保存当前画布状态 + int saveCount = canvas.save(); + canvas.clipPath(path);//裁剪子布局超出圆角的部分 + super.dispatchDraw(canvas); //然后绘制子视图 + + //开始绘制描边 + Paint borderPaint = new Paint(); + borderPaint.setColor(tBorderColor); //设置描边颜色 + borderPaint.setStyle(Paint.Style.STROKE); + borderPaint.setStrokeWidth(tBorderSize); //设置描边宽度 + canvas.drawPath(path, borderPaint);//沿圆角路径绘制描边 + //恢复画布状态 + canvas.restoreToCount(saveCount); + } + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + //判断是否为渐变类型 + public boolean isGdType(int typeIndex) { + return typeIndex == GradientDrawable.LINE || + typeIndex == GradientDrawable.LINEAR_GRADIENT || + typeIndex == GradientDrawable.OVAL || + typeIndex == GradientDrawable.RADIAL_GRADIENT || + typeIndex == GradientDrawable.RECTANGLE || + typeIndex == GradientDrawable.RING || + typeIndex == GradientDrawable.SWEEP_GRADIENT; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiV.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiV.java new file mode 100644 index 0000000..6b979f8 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiV.java @@ -0,0 +1,773 @@ +package com.bytecat.algui.AlguiViews; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.Typeface; +import android.os.Handler; +import android.text.InputType; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.TextView; +import com.bytecat.algui.AlguiHacker.AlguiRootClient; +import com.bytecat.algui.AlguiHacker.AlguiRootService; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import com.bytecat.algui.AlguiTools.AlguiToolNetwork; +import com.bytecat.algui.AlguiViews.AlguiLinearLayout; +import com.bytecat.algui.AlguiViews.AlguiViewButton; +import com.bytecat.algui.AlguiViews.AlguiViewCheckBox; +import com.bytecat.algui.AlguiViews.AlguiViewDragBar; +import com.bytecat.algui.AlguiViews.AlguiViewFoldMenu; +import com.bytecat.algui.AlguiViews.AlguiViewImage; +import com.bytecat.algui.AlguiViews.AlguiViewInputBox; +import com.bytecat.algui.AlguiViews.AlguiViewItem; +import com.bytecat.algui.AlguiViews.AlguiViewLine; +import com.bytecat.algui.AlguiViews.AlguiViewSoundWave; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import com.bytecat.algui.AlguiViews.AlguiViewTriangle; +import com.bytecat.algui.AlguiViews.AlguiViewWeb; +import com.bytecat.algui.AlguiWindows.AlguiWinConsole; +import com.bytecat.algui.AlguiWindows.AlguiWinDialog; +import com.bytecat.algui.AlguiWindows.AlguiWinInform; +import com.bytecat.algui.AlguiWindows.AlguiWinMenu; +import com.bytecat.algui.AlguiWindows.AlguiWindow; +import com.bytecat.algui.ui.AlguiActivity; +import com.topjohnwu.superuser.ipc.RootService; +import java.util.ArrayList; +import android.animation.ValueAnimator; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/22 21:48 + * @Describe Algui快速构建器 + 声明:以下只提供简单封装给不会使用的人快速使用 + 因此还有很多特性没有封装自己利用以下方法进行挖掘,[查阅AlguiSDK.java文件] + + 图片 + 均支持:网络图片链接,base64编码,本地图片文件路径,图片文件名(识别为assets文件夹下的) + 格式均支持:GIF动图(.gif),普通图片(.png .jpg) + + 高度化定制教程: + 调用封装方法后调用.setCat...会出现和此组件相关的设置样式属性等等的提示,看得懂英文就很简单 + 比如: + Text(layout,"文本").setCatTextColor(0xFFFFFFFF); + 就是创建文本后设置文本颜色为白色 + + 调用封装方法后.getByte...是获取和此组件绑定的某些子对象,可以自定义这些子对象的属性 + 比如: + WinMenu("菜单窗口").getByteMenuBottomLayout().addView(Text(null,"关闭")); + 就是创建菜单窗口后获取菜单窗口底部布局并在底部布局添加一个文本 + */ + +public class AlguiV { + + public static final String TAG = "AlguiV"; + + + //单例 + private static Context aContext; // 确保 aContext 被正确声明 + private static AlguiV obj; + private AlguiV(Context context) {aContext = context;} + public static AlguiV Get(Context context) { + if (obj == null) + obj = new AlguiV(context); + return obj; + } + + + + //&&&&&&&&&&&&&&&&&&&&&&对于窗口&&&&&&&&&&&&&&&&&&&&&& + //创建一个普通菜单窗口 + public AlguiWinMenu WinMenu(CharSequence title, Object... args) { + AlguiWinMenu obj=new AlguiWinMenu(aContext) + .setCatMenuTitle(title, args) + .showBall() + ; + return obj; + } + //创建一个日志控制台窗口 + //使用AlguiLog.i("标签","信息") 在控制台输出信息 + //哪里都可以向控制台输出,无需担心非UI线程 + public AlguiWinConsole WinLog() { + return AlguiLog.getLogConsole(aContext).show(); + } + + //创建一个文本对话框窗口 + public AlguiWinDialog WinDialogText(int style[], CharSequence title, CharSequence text, Object... args) { + final AlguiWinDialog dialog = new AlguiWinDialog(aContext) + .setCatIsCanEnd(true) + .setCatStyle(style) + .setCatIcon(AlguiAssets.Icon.inform_info) + .setCatTitle(title, args) + .setCatNoButtonText(null) + .setCatNoButtonClick(null) + .setCatYesButtonText("我知道了") + .show(); + dialog.setCatYesButtonClick(new AlguiCallback.Click() { + public void click(boolean b) { + dialog.end(); + } + }); + + new AlguiViewText(aContext) + .setCatText(text, args) + .setCatTextColor(style[1]) + .setCatTextSize(9) + .setCatParentLayout(dialog); + + return dialog; + } + //创建一个文本对话框窗口 (黑色) + public AlguiWinDialog WinDialogText_Black(CharSequence title, CharSequence text, Object... args) { + return WinDialogText(AlguiWinDialog.Style.BLACK, title, text, args); + } + //创建一个文本对话框窗口 (白色) + public AlguiWinDialog WinDialogText_White(CharSequence title, CharSequence text, Object... args) { + return WinDialogText(AlguiWinDialog.Style.WHITE, title, text, args); + } + //创建一个文本对话框窗口 (蓝色) + public AlguiWinDialog WinDialogText_Blue(CharSequence title, CharSequence text, Object... args) { + return WinDialogText(AlguiWinDialog.Style.BLUE, title, text, args); + } + + //发送一个通知到通知窗口(黑色) + public AlguiWinInform WinSendInfo_Black(String Image_Url_Base64_FilePath, CharSequence titleText, CharSequence infoText, int showTime) { + return AlguiWinInform.Get(aContext) .showInfo_Black(Image_Url_Base64_FilePath, titleText, infoText, showTime); + } + //发送一个通知到通知窗口(白色) + public AlguiWinInform WinSendInfo_White(String Image_Url_Base64_FilePath, CharSequence titleText, CharSequence infoText, int showTime) { + return AlguiWinInform.Get(aContext) .showInfo_White(Image_Url_Base64_FilePath, titleText, infoText, showTime); + } + //发送一个通知到通知窗口(蓝色) + public AlguiWinInform WinSendInfo_Blue(String Image_Url_Base64_FilePath, CharSequence titleText, CharSequence infoText, int showTime) { + return AlguiWinInform.Get(aContext) .showInfo_Blue(Image_Url_Base64_FilePath, titleText, infoText, showTime); + } + + //静态绘制视图到屏幕指定坐标 参数传视图,坐标原点,xy坐标相对原点偏移,悬浮视图是否可点击 + //如果需要高性能的动态帧绘制请使用AlguiWinDraw + public AlguiWindow WinDraw(View v, int gravity, float x, float y, boolean isClick) { + AlguiWindow w = new AlguiWindow(aContext) + .setCatPosGravity(gravity) + .setCatPos(x, y) + .setCatView(v) + .show() + ; + if (!isClick) + w.addFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + return w; + } + + //&&&&&&&&&&&&&&&&&&&&&&对于布局&&&&&&&&&&&&&&&&&&&&&& + + + + //&&&&&&&&&&&&&&&&&&&&&&对于折叠菜单&&&&&&&&&&&&&&&&&&&&&& + //创建一个普通折叠菜单 + public AlguiViewFoldMenu FoldMenu(ViewGroup fatherLayout, CharSequence title) { + AlguiViewFoldMenu obj=new AlguiViewFoldMenu(aContext) + .setCatText(title) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个子折叠菜单 + public AlguiViewFoldMenu FoldMenuSon(ViewGroup fatherLayout, CharSequence title) { + AlguiViewFoldMenu obj=new AlguiViewFoldMenu(aContext) + .setCatTextSize(6.5f) + .setCatTitleBackColor(0) + .setCatText(title) + .setCatParentLayout(fatherLayout) + ; + obj.getByteTitleLayout().setCatPadding(6, 0, 6, 0); + return obj; + } + //创建一个单选折叠菜单 传标题,切换选项监听器,选项文本列表(添加顺序决定ID,0开始) + public AlguiViewItem FoldMenuSwitch(ViewGroup fatherLayout, CharSequence title, final AlguiCallback.Item call, final CharSequence... items) { + AlguiLinearLayout tL=new AlguiLinearLayout(aContext) + .setCatMargins(5, 0, 0, 0) + .setCatPadding(5, 5, 5, 5) + .setCatBackColor(0xFF274A72) + ; + AlguiViewTriangle t = new AlguiViewTriangle(aContext) + .setCatSize(5) + .setCatColor(0xFFFFFFFF) + .setCatType(AlguiViewTriangle.Type.EQUILATERAL_TOP) + .setCatParentLayout(tL) + ; + + final AlguiViewItem obj=new AlguiViewItem(aContext) + //.setCatSize(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT) + //.setCatWeight(0) + .setCatPadding(5, 0, 0, 0) + .setCatBackColor(0xFF20324D) + .setCatText(title) + .setCatParentLayout(fatherLayout) + .addItem(0, tL) + ; + + obj.setCatCallback(new AlguiCallback.Item(){ + boolean isInit=false; + + AlguiLinearLayout layout; + PopupWindow popupWindow; + ArrayList itemVs = new ArrayList<>(); + int sel=0; + public void item(int b) { + if (!isInit) { + + layout = new AlguiLinearLayout(aContext); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setGravity(Gravity.CENTER_HORIZONTAL); + layout.setCatBackColor(0xce000000); + + //滚动列表 + int i=0; + for (final CharSequence text:items) { + if (text != null) { + final AlguiViewItem v =new AlguiViewItem(aContext, text); + v.setCatBackColor(0); + v.setCatText(text); + v.setCatId(i); + v.setCatCallback(new AlguiCallback.Item(){ + public void item(int u) { + obj.setCatText(text); + popupWindow.dismiss(); + if (call != null) + call.item(v.getByteId()); + sel = v.getByteId(); + } + } + ); + layout.addView(v); + itemVs.add(v); + i++; + } + } + popupWindow = new PopupWindow(layout, obj.getWidth(), LinearLayout.LayoutParams.WRAP_CONTENT); + + popupWindow.setOutsideTouchable(true); + isInit = true; + } + popupWindow.setWidth(obj.getWidth()); + for (AlguiViewItem v: itemVs) { + if (v != null) { + if (v.getByteId() == sel) { + v.select(); + } + } + + } + popupWindow.showAsDropDown(obj, 0, 0); + } + } + ); + + return obj; + } + + + //&&&&&&&&&&&&&&&&&&&&&&对于文本&&&&&&&&&&&&&&&&&&&&&& + //创建一个普通文本 + public AlguiViewText Text(ViewGroup fatherLayout, CharSequence text, Object... args) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatText(text, args) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个Html文本 + public AlguiViewText TextHtml(ViewGroup fatherLayout, String text, Object... args) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatTextHtml(text, args) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个自动识别文本中链接的文本 + public AlguiViewText Textlink(ViewGroup fatherLayout, CharSequence text, Object... args) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatText(text, args) + .setCatTextIsLink(true) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个文本标题 + public AlguiViewText TextTitle(ViewGroup fatherLayout, CharSequence text, Object... args) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatTextSize(9) + .setCatTextTFAssets("lz.ttf", Typeface.BOLD) + .setCatText(text, args) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个子文本 + public AlguiViewText TextSon(ViewGroup fatherLayout, CharSequence text, Object... args) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatText(" • " + text, args) + .setCatTextColor(0xFFBDBDBD) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个文本信息框 + public AlguiViewInputBox TextInfo(ViewGroup fatherLayout, CharSequence text) { + AlguiViewInputBox obj=new AlguiViewInputBox(aContext) + .setCatSize(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + .setCatWeight(1) + .setCatButtonText(null) + .setCatInputText(text) + .setCatInputTextColor(0xFFFFFFFF) + //.setCatPadding(3, 3, 3, 3) + .setCatBackColor(0xFF20324D) + .setCatBorder(0.4f, 0xff294A7A) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个文本标签 + public AlguiViewText TextTag(ViewGroup fatherLayout, CharSequence text, int color, Object... args) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatText(text, args) + .setCatPadding(2, 0, 2, 0) + .setCatTextColor(0xFFFFFFFF) + .setCatBackColor(color) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个可弹出提示的帮助文本 + public AlguiViewText TextHelp(ViewGroup fatherLayout, CharSequence title, final CharSequence text, final Object... args) { + final AlguiViewText obj=new AlguiViewText(aContext) + .setCatText("[" + title + "]", args) + .setCatTextColor(0xAEADB1B7) + .setCatParentLayout(fatherLayout) + ; + obj.setCatCallback(new AlguiCallback.Click(){ + boolean isInit=false; + AlguiViewText textV; + PopupWindow popupWindow; + public void click(boolean b) { + if (!isInit) { + + textV = new AlguiViewText(aContext) + .setCatText(text, args) + .setCatPadding(5, 2, 5, 2) + .setCatBackColor(0xce151617) + //.setCatBorder(0.4f, 0xCEADB1B7) + ; + + popupWindow = new PopupWindow(textV, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + popupWindow.setOutsideTouchable(true); + isInit = true; + } + + popupWindow.showAsDropDown(obj, 0, 0); + } + } + ); + return obj; + } + //创建一个滚动文本 + public AlguiViewText TextRoll(ViewGroup fatherLayout, CharSequence text, Object... args) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatText(text, args) + .setCatSize(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + .setCatWeight(1) + .setCatTextRoll(true) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个渐变文本 + public AlguiViewText TextColors(ViewGroup fatherLayout, CharSequence text, int... colors) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatText(text) + .setCatTextColor(colors) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个动态渐变文本 + public AlguiViewText TextColorsMove(ViewGroup fatherLayout, CharSequence text, int... colors) { + AlguiViewText obj=new AlguiViewText(aContext) + .setCatText(text) + .setCatTextColor(colors) + .setCatTextMoveGrad(true) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + + + //&&&&&&&&&&&&&&&&&&&&&&对于按钮&&&&&&&&&&&&&&&&&&&&&& + //创建一个普通按钮 + public AlguiViewButton Button(ViewGroup fatherLayout, CharSequence text) { + AlguiViewButton obj=new AlguiViewButton(aContext) + .setCatText(text) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个长按钮 + public AlguiViewButton ButtonLong(ViewGroup fatherLayout, CharSequence text) { + AlguiViewButton obj=new AlguiViewButton(aContext) + .setCatSize(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + .setCatWeight(1) + .setCatText(text) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个切换选项的按钮 传选项列表 每个选项都是一个视图 它们的ID自动根据添加顺序从0开始0,1,2... + public AlguiViewItem SwitchItem(ViewGroup fatherLayout, CharSequence text, View... items) { + AlguiViewItem obj=new AlguiViewItem(aContext) + .setCatText(text) + .setCatParentLayout(fatherLayout) + .addItem(items) + ; + return obj; + } + + //创建一个长按钮项 + public AlguiViewItem ButtonItemLong(ViewGroup fatherLayout, CharSequence text) { + AlguiViewItem obj=new AlguiViewItem(aContext) + .setCatText(text) + .setCatSize(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + .setCatWeight(0) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个按钮项 + public AlguiViewItem ButtonItem(ViewGroup fatherLayout, CharSequence text) { + AlguiViewItem obj=new AlguiViewItem(aContext) + .setCatText(text) + .setCatSize(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + .setCatWeight(0) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个图标按钮项 + public AlguiViewItem ButtonIcon(ViewGroup fatherLayout, CharSequence text, String Url_Base64_FilePath) { + AlguiViewItem obj=new AlguiViewItem(aContext) + .setCatText(text) + .setCatSize(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + .setCatWeight(0) + .setCatIcon(Url_Base64_FilePath) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个勾选项 监听器判断0未选中1选中 + public AlguiViewItem TickItem(ViewGroup fatherLayout, CharSequence text) { + View v=new View(aContext); + v.setVisibility(View.GONE); + AlguiViewItem obj=new AlguiViewItem(aContext) + .setCatText(text) + .setCatParentLayout(fatherLayout) + .addItem(0, v) + .addItem(1, new AlguiViewImage(aContext, AlguiAssets.Icon.hook).setCatSize(11, 11).setCatColor(0xFFFFFFFF)) + ; + return obj; + } + //创建一个切换开关选项按钮 监听器判断0关1开 + public AlguiViewItem Switch(ViewGroup fatherLayout, CharSequence text) { + AlguiViewItem obj=new AlguiViewItem(aContext) + .setCatText(text) + .setCatParentLayout(fatherLayout) + .addItem(0, new AlguiViewText(aContext, "关闭")) + .addItem(1, new AlguiViewText(aContext, "开启")) + ; + return obj; + } + //创建一个普通复选框 + public AlguiViewCheckBox CheckBox(ViewGroup fatherLayout, CharSequence text) { + AlguiViewCheckBox obj=new AlguiViewCheckBox(aContext) + .setCatText(text) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + + + + + //&&&&&&&&&&&&&&&&&&&&&&对于拖动条&&&&&&&&&&&&&&&&&&&&&& + //进度设置文本时占位符{v}代表当前进度 例如:进度{v}% 最终显示:进度30% 没有占位符时进度默认加在文本后面 + //创建一个普通拖动条,自定义小数位和递增递减按钮在哪个小数位调节 + public AlguiViewDragBar Drag(ViewGroup fatherLayout, CharSequence text, double min, double def, double max, int bit, int tuneBit) { + AlguiViewDragBar obj=new AlguiViewDragBar(aContext) + .setCatText(text) + .setCatValueBit(bit) + .setCatValueTuneBit(tuneBit) + .setCatValueMin(min) + .setCatValueMax(max) + .setCatValue(def) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个整数拖动条 + public AlguiViewDragBar DragInt(ViewGroup fatherLayout, CharSequence text, int min, int def, int max) { + return Drag(fatherLayout, text, min, def, max, 0, 0); + } + //创建一个一位小数拖动条 + public AlguiViewDragBar DragFloat1(ViewGroup fatherLayout, CharSequence text, float min, float def, float max) { + return Drag(fatherLayout, text, min, def, max, 1, 1); + } + //创建一个两位小数拖动条 + public AlguiViewDragBar DragFloat2(ViewGroup fatherLayout, CharSequence text, float min, float def, float max) { + return Drag(fatherLayout, text, min, def, max, 2, 2); + } + //创建一个三位小数拖动条 + public AlguiViewDragBar DragFloat3(ViewGroup fatherLayout, CharSequence text, float min, float def, float max) { + return Drag(fatherLayout, text, min, def, max, 3, 3); + } + + + + + + //&&&&&&&&&&&&&&&&&&&&&&对于输入框&&&&&&&&&&&&&&&&&&&&&& + //创建一个普通文本输入框 + public AlguiViewInputBox InputText(ViewGroup fatherLayout, CharSequence text) { + return InputText(fatherLayout, text, null); + } + //创建一个普通文本输入框 (带按钮) + public AlguiViewInputBox InputText(ViewGroup fatherLayout, CharSequence text, CharSequence bText) { + AlguiViewInputBox obj=new AlguiViewInputBox(aContext) + .setCatButtonText(bText) + .setCatInputHint(text) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个整数输入框 + public AlguiViewInputBox InputInt(ViewGroup fatherLayout, CharSequence text) { + return InputInt(fatherLayout, text, null); + } + //创建一个整数输入框 (带按钮) + public AlguiViewInputBox InputInt(ViewGroup fatherLayout, CharSequence text, CharSequence bText) { + AlguiViewInputBox obj=new AlguiViewInputBox(aContext) + .setCatButtonText(bText) + .setCatInputHint(text) + .setCatInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个小数输入框 + public AlguiViewInputBox InputFloat(ViewGroup fatherLayout, CharSequence text) { + return InputFloat(fatherLayout, text, null); + } + //创建一个小数输入框 (带按钮) + public AlguiViewInputBox InputFloat(ViewGroup fatherLayout, CharSequence text, CharSequence bText) { + AlguiViewInputBox obj=new AlguiViewInputBox(aContext) + .setCatButtonText(bText) + .setCatInputHint(text) + .setCatInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED | InputType.TYPE_NUMBER_FLAG_DECIMAL) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + + + + + //&&&&&&&&&&&&&&&&&&&&&&对于其它&&&&&&&&&&&&&&&&&&&&&& + + //创建一个普通图片 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiViewImage Image(ViewGroup fatherLayout, String Url_Base64_FilePath) { + AlguiViewImage obj=new AlguiViewImage(aContext) + .setCatSize(50, 50) + .setCatImage(Url_Base64_FilePath) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + + //创建一个普通网页视图 支持 加载网站,加载HTML代码,加载HTML文件 + public AlguiViewWeb Web(ViewGroup fatherLayout, String website_htmlcode_htmlfile) { + AlguiViewWeb obj=new AlguiViewWeb(aContext, AlguiActivity.MainActivity) + .setCatWeb(website_htmlcode_htmlfile) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个普通三角形 + public AlguiViewTriangle Triangle(ViewGroup fatherLayout, int dirType) { + AlguiViewTriangle obj=new AlguiViewTriangle(aContext) + .setCatType(dirType) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个普通声音监测视图 + public AlguiViewSoundWave SoundMonitoring(ViewGroup fatherLayout, int style) { + AlguiViewSoundWave obj=new AlguiViewSoundWave(aContext, AlguiActivity.MainActivity) + .setCatStyle(style) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个线条 (自定义样式) + public AlguiViewLine Line(ViewGroup fatherLayout, int color, int style) { + AlguiViewLine obj=new AlguiViewLine(aContext) + .setCatStyle(style) + .setCatColor(color) + .setCatParentLayout(fatherLayout) + ; + return obj; + } + //创建一个线条 + public AlguiViewLine Line(ViewGroup fatherLayout, int color) { + return Line(fatherLayout, color, AlguiViewLine.Style.STYLE_SOLID); + } + + + + + //&&&&&&&&&&&&&&&&&&&&&&预制内容&&&&&&&&&&&&&&&&&&&&&& + + //选择运行环境对话框 + public void WinDialogEnv() { + AlguiToolNetwork.GET("https://v1.hitokoto.cn/?&encode=text&c=a", null , new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + if (response == null) + return; + + final AlguiWinDialog dialog= WinDialogText_White("请选择运行环境", response); + dialog.setCatIsCanEnd(false); + dialog.setCatNoButtonText("正常环境"); + dialog.setCatNoButtonClick(new AlguiCallback.Click(){ + public void click(boolean sb) { + dialog.end(); + } + + } + ); + dialog.setCatYesButtonText("ROOT环境"); + dialog.setCatYesButtonClick(new AlguiCallback.Click(){ + public void click(boolean sb) { + boolean b = AlguiRootService.isConnect(); + if (!b) { + AlguiRootService.setCallBack(new AlguiCallback.RootService(){ + public void rootService(boolean isOK) { + if (isOK) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_info_gta5); + AlguiWinInform.Get(aContext).showInfo_White(AlguiAssets.Icon.magisk, "Root环境加载成功", "请谨慎操作,避免数据丢失!", 5); + + } else { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_alert); + AlguiWinInform.Get(aContext).showInfo_White(AlguiAssets.Icon.inform_info2, "Root环境已断开", null, 5); + } + } + } + ); + RootService.bind(new Intent(aContext, AlguiRootClient.class), new AlguiRootService()); + } else { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_info_gta5); + AlguiWinInform.Get(aContext).showInfo_White(AlguiAssets.Icon.magisk, "Root环境加载成功", "请谨慎操作,避免数据丢失!", 5); + } + dialog.end(); + } + + } + ); + } + //请求失败 + @Override + public void onFailure(String error) { + + } + }); + + + + } + + + +/* ---------- 电视机无信号飘动文字(实例化版,Java 7 及以下) ---------- */ +public static class TVNoSignalText { + + private final AlguiWindow win; + private final android.animation.ValueAnimator anim; + private float x, y, vx, vy; + private int w, h, txtW, txtH; + + public TVNoSignalText() { + win = new AlguiWindow(aContext) + .setCatActivity(aContext) + .setCatTransparent(0.7f) + .setCatFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + anim = android.animation.ValueAnimator.ofFloat(0, 1); + anim.setDuration(16); + anim.setRepeatCount(android.animation.ValueAnimator.INFINITE); + anim.addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(android.animation.ValueAnimator animation) { + x += vx; + y += vy; + + w = win.getByteWindowManager().getDefaultDisplay().getWidth(); + h = win.getByteWindowManager().getDefaultDisplay().getHeight(); + + if (x <= 0 || x + txtW >= w) vx = -vx; + if (y <= 0 || y + txtH >= h) vy = -vy; + + x = Math.max(0, Math.min(x, w - txtW)); + y = Math.max(0, Math.min(y, h - txtH)); + + win.setPos((int) x, (int) y).update(); + } + }); + } + + /** 开始飘动 */ + public void start(String text) { + TextView tv = new TextView(win.getByteContext()); + tv.setText(text); + tv.setTextColor(0x2BFFFFFF); + tv.setTextSize(15); + tv.setTypeface(Typeface.createFromAsset(win.getByteContext().getAssets(), "ztt.ttf")); + + tv.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + txtW = tv.getMeasuredWidth(); + txtH = tv.getMeasuredHeight(); + win.setCatView(tv); + + w = win.getByteWindowManager().getDefaultDisplay().getWidth(); + h = win.getByteWindowManager().getDefaultDisplay().getHeight(); + x = w / 2f - txtW / 2f; + y = h / 2f - txtH / 2f; + vx = (float) ((Math.random() * 2 + 1) * (Math.random() > 0.5 ? 1 : -1) * 0.4); +vy = (float) ((Math.random() * 2 + 1) * (Math.random() > 0.5 ? 1 : -1) * 0.4); + + anim.start(); + win.show(); + } + + /** 停止飘动 */ + public void stop() { + anim.cancel(); + win.hide(); + } +} + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewButton.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewButton.java new file mode 100644 index 0000000..5864c3e --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewButton.java @@ -0,0 +1,211 @@ +package com.bytecat.algui.AlguiViews; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/11/12 21:09 + * @Describe Algui按钮 + */ +import android.content.Context; +import android.graphics.Typeface; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import com.bytecat.algui.AlguiManager.AlguiCallback; + +public class AlguiViewButton extends AlguiViewText { + + public static final String TAG = "AlguiViewButton"; + + //点击事件回调反馈 + AlguiCallback.Click call; + boolean isInitClick = false;//是否已经初始化点击事件 + boolean isChecked = false; + //初始化内部点击事件 + private void initClick() { + setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + //按下 + case MotionEvent.ACTION_DOWN: + //进行宽高90%缩放动画 + v.animate().scaleX(0.90f).scaleY(0.90f).setDuration(100); + + break; + //松开 + case MotionEvent.ACTION_UP: + //恢复缩放动画 + v.animate().scaleX(1f).scaleY(1f).setDuration(100); + callClick(!isChecked);//执行点击事件 + break; + //事件取消时执行 (备份一份恢复操作放在这里 防止在动画期间迅速关闭窗口时动画卡一半崩溃) + case MotionEvent.ACTION_CANCEL: + //恢复缩放动画 + v.animate().scaleX(1f).scaleY(1f).setDuration(100); + + break; + } + return true; + } + }); + isInitClick = true; + } + //设置点击事件回调反馈接口 + public AlguiViewButton setCatCallback(AlguiCallback.Click c) { + if (c == null) { + setOnTouchListener(null); + isInitClick = false; + } else { + call = c; + if (!isInitClick) { + initClick(); + } + } + return this; + } + //获取点击事件回调反馈接口 + public AlguiCallback.Click getByteCallback() { + return call; + } + //代码执行点击事件 + public AlguiViewButton callClick(boolean b) { + isChecked = b; + if (call != null) + call.click(isChecked);//回调 + return this; + } + + + + + //设置文本发光效果 + public AlguiViewButton setCatTextGlow(float radius, int color) { + super.setCatTextGlow(radius, color); + return this; + } + //设置文本动态渐变效果启动状态 + public AlguiViewButton setCatTextMoveGrad(boolean b) { + super.setCatTextMoveGrad(b); + return this; + } + //设置文本渐变速度 + public AlguiViewButton setCatTextGradSpeed(float s) { + super.setCatTextGradSpeed(s); + return this; + } + //设置文本滚动效果启动状态 + public AlguiViewButton setCatTextRoll(boolean b) { + super.setCatTextRoll(b); + return this; + } + //设置文本滚动速度 + public AlguiViewButton setCatTextRollSpeed(float s) { + super.setCatTextRollSpeed(s); + return this; + } + //设置文本 + public AlguiViewButton setCatText(CharSequence text,Object... args) { + super.setCatText(text,args); + return this; + } + //设置Html文本 + public AlguiViewButton setCatTextHtml(String text) { + super.setCatTextHtml(text); + return this; + } + //设置文本颜色 + public AlguiViewButton setCatTextColor(int... color) { + super.setCatTextColor(color); + return this; + } + //设置文本大小 + public AlguiViewButton setCatTextSize(float size) { + super.setCatTextSize(size); + return this; + } + //设置Assets文件夹字体文件作为文本字体 + public AlguiViewButton setCatTextTFAssets(String assetsTfFileName) { + super.setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewButton setCatTextTFAssets(String assetsTfFileName, int style) { + super.setCatTextTFAssets(assetsTfFileName, style); + return this; + } + //设置文本重力 + public AlguiViewButton setCatTextGravity(int g) { + super.setCatTextGravity(g); + return this; + } + //设置文本是否响应超链接 + public AlguiViewButton setCatTextIsLink(boolean b) { + super.setCatTextIsLink(b); + return this; + } + + //设置布局大小 + public AlguiViewButton setCatSize(float w, float h) { + super.setCatSize(w, h); + return this; + } + + //设置权重 + public AlguiViewButton setCatWeight(float weight) { + super.setCatWeight(weight); + return this; + } + + //设置内边距 + public AlguiViewButton setCatPadding(float left, float top, float right, float bottom) { + super.setCatPadding(left, top, right, bottom); + return this; + } + + //设置外边距 + public AlguiViewButton setCatMargins(float left, float top, float right, float bottom) { + super.setCatMargins(left, top, right, bottom); + return this; + } + + //设置背景颜色 + public AlguiViewButton setCatBackColor(int... backColor) { + super.setCatBackColor(backColor); + return this; + } + //设置圆角半径 + public AlguiViewButton setCatRadiu(float r) { + super.setCatRadiu(r); + return this; + } + //设置描边 + public AlguiViewButton setCatBorder(float size, int color) { + super.setCatBorder(size, color); + return this; + } + + //设置父布局 + public AlguiViewButton setCatParentLayout(ViewGroup vg) { + super.setCatParentLayout(vg); + return this; + } + + + public AlguiViewButton(Context c) { + super(c); + setCatText(TAG);//设置文本 + setCatTextSize(7);//文本大小 + setCatTextColor(0xffADB1B7);//文本颜色 + setCatTextGravity(Gravity.CENTER);//文本对齐方式 + setCatPadding(5, 3, 5, 3);//内边距 + setCatBackColor(0xff274A72);//设置背景颜色 (支持多颜色渐变) + initClick();//初始化内部点击事件 + } + + public AlguiViewButton(Context c, CharSequence text) { + this(c); + setCatText(text); + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewCheckBox.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewCheckBox.java new file mode 100644 index 0000000..34db4bb --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewCheckBox.java @@ -0,0 +1,291 @@ +package com.bytecat.algui.AlguiViews; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/11/08 17:09 + * @Describe Algui复选框 + */ +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Typeface; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiViews.AlguiFrameLayout; + +public class AlguiViewCheckBox extends AlguiLinearLayout { + + public static final String TAG = "AlguiViewCheckBox"; + + Context aContext; + AlguiFrameLayout box;//复选框盒子 + AlguiViewImage selectIcon;//复选框选中视图 + AlguiViewText title;//复选框标题 + + + // 获取复选框盒子 + public AlguiFrameLayout getByteBox() { + return box; + } + + + + // 获取复选框选中图标 + public AlguiViewImage getByteSelectIcon() { + return selectIcon; + } + + + + // 获取复选框标题 + public AlguiViewText getByteTitle() { + return title; + } + + + + + //点击事件回调反馈 + boolean isSelect = false; // 复选框选中状态 + AlguiCallback.Click call; + boolean isInitClick=false;//是否已经初始化点击事件 + //初始化内部点击事件 + private void initClick() { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + setCatSelect(!isSelect);//执行点击切换选中状态 + } + }); + isInitClick = true; + } + //设置点击事件回调反馈接口 + public AlguiViewCheckBox setCatCallback(AlguiCallback.Click c) { + if (c == null) { + setOnClickListener(null); + isInitClick = false; + } else { + call = c; + if (!isInitClick) { + initClick(); + } + } + return this; + } + //获取点击事件回调反馈接口 + public AlguiCallback.Click getByteCallback() { + return call; + } + //设置选中状态 + public AlguiViewCheckBox setCatSelect(boolean isSelect) { + this.isSelect = isSelect; + + selectIcon.setVisibility(isSelect ?View.VISIBLE: View.GONE);//控制选中图标显隐 + + if (call != null) + call.click(isSelect);//回调 + return this; + } + + + + //继承修复父类方法链,让父类方法链嵌套在子类的方法链中 + // 设置大小 + public AlguiViewCheckBox setCatSize(float w, float h) { + super.setCatSize(w, h); // 调用父类的 setCatSize 方法 + return this; + } + + // 设置权重 + public AlguiViewCheckBox setCatWeight(float weight) { + super.setCatWeight(weight); // 调用父类的 setCatWeight 方法 + return this; + } + + // 设置内边距 + public AlguiViewCheckBox setCatPadding(float left, float top, float right, float bottom) { + super.setCatPadding(left, top, right, bottom); // 调用父类的 setCatPadding 方法 + return this; + } + + // 设置外边距 + public AlguiViewCheckBox setCatMargins(float left, float top, float right, float bottom) { + super.setCatMargins(left, top, right, bottom); // 调用父类的 setCatMargins 方法 + return this; + } + + // 设置背景颜色 + public AlguiViewCheckBox setCatBackColor(int... backColor) { + super.setCatBackColor(backColor); // 调用父类的 setCatBackColor 方法 + return this; + } + + // 设置圆角半径 + public AlguiViewCheckBox setCatRadiu(float radiu) { + super.setCatRadiu(radiu); // 调用父类的 setCatRadiu 方法 + return this; + } + + // 设置描边 + public AlguiViewCheckBox setCatBorder(float borderSize, int borderColor) { + super.setCatBorder(borderSize, borderColor); // 调用父类的 setCatBorder 方法 + return this; + } + + // 设置父布局 + public AlguiViewCheckBox setCatParentLayout(ViewGroup vg) { + super.setCatParentLayout(vg); // 调用父类的 setCatParentLayout 方法 + return this; + } + + + // 设置文本大小 + public AlguiViewCheckBox setCatTextSize(float size) { + title.setCatTextSize(size);//设置标题大小 + //盒子应该为正方形,并且大小随标题x2 + box.setCatSize(size * 2.1f, size * 2.1f); + super.setCatSize(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + + return this; + } + + //设置盒子圆角 + public AlguiViewCheckBox setCatBoxRadiu(float r) { + box.setCatRadiu(r); + return this; + } + + //设置盒子描边 + public AlguiViewCheckBox setCatBoxBorder(float size, int color) { + box.setCatBorder(size, color); + return this; + } + + //设置盒子背景颜色 + public AlguiViewCheckBox setCatBoxBackColor(int... color) { + box.setCatBackColor(color); + return this; + } + //设置盒子图标颜色 + public AlguiViewCheckBox setCatBoxIconColor(int color) { + selectIcon.setCatColor(color); + return this; + } + + //设置盒子选中图标 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiViewCheckBox setCatBoxIcon(String Url_Base64_AssetsFile) { + selectIcon.setCatImage(Url_Base64_AssetsFile); + return this; + } + + + //设置文本 + public AlguiViewCheckBox setCatText(CharSequence text,Object... args) { + title.setCatText(text,args); + return this; + } + + //设置文本颜色 + public AlguiViewCheckBox setCatTextColor(int... color) { + title.setCatTextColor(color); + + return this; + } + //设置文本动态渐变效果启动状态 + public AlguiViewCheckBox setCatTextMoveGrad(boolean b) { + title.setCatTextMoveGrad(b); + return this; + } + //设置文本发光 + public AlguiViewCheckBox setCatTextGlow(float radius, int color) { + title.setCatTextGlow(radius, color); + return this; + } + + //设置Assets文件夹字体文件作为文本字体 + public AlguiViewCheckBox setCatTextTFAssets(String assetsTfFileName) { + title.setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewCheckBox setCatTextTFAssets(String assetsTfFileName, int style) { + title.setCatTextTFAssets(assetsTfFileName, style); + return this; + } + //设置选中图标可见性 + /*public AlguiCheckBox setIconVisibility(boolean b) { + if (b) { + selectIcon.setVisibility(View.VISIBLE);//显示选中视图 + } else { + selectIcon.setVisibility(View.GONE);//隐藏选中视图 + } + isSelect = b; + return this; + }*/ + + public AlguiViewCheckBox(Context c) { + super(c); + aContext = c; + init(); + } + + public AlguiViewCheckBox(Context c, CharSequence text) { + this(c); + title.setCatText(text); + } + private void init() { + //根布局 + setCatSize(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + setOrientation(LinearLayout.HORIZONTAL);//横向 + setGravity(Gravity.CENTER_VERTICAL);//垂直居中 + //复选框容器 + box = new AlguiFrameLayout(aContext); + box.setCatMargins(0, 0, 3f, 0);//外边距 + box.setCatPadding(1, 1, 1, 1); + box.setCatBackColor(0xFF20324D);//背景颜色 + //复选框选中视图 + selectIcon = new AlguiViewImage(aContext); + selectIcon.setCatImageBase64(AlguiAssets.Icon.hook); + selectIcon.setCatColor(0xFF4296FA); + //标题 + title = new AlguiViewText(aContext); + title.setCatSize(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + title.setCatText(TAG); + title.setCatTextColor(0xFFADB1B7); + title.setCatMargins(0, 0, 3f, 0);//外边距 + + box.addView(selectIcon);//复选框容器添加选中视图 + addView(box);//根布局添加复选框容器 + addView(title);//根布局添加标题 + + initClick(); + setCatSelect(isSelect);//默认选中状态 + setCatTextSize(7);//设置缩放大小 + + } + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewDragBar.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewDragBar.java new file mode 100644 index 0000000..c58a27c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewDragBar.java @@ -0,0 +1,726 @@ +package com.bytecat.algui.AlguiViews; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/15 13:49 + * @Describe Algui拖动条 (只针对于横向拖动条不支持竖向) + */ +import android.content.Context; +import android.graphics.Typeface; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Build; +import android.text.SpannableStringBuilder; +import android.view.Gravity; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import java.util.Arrays; + +public class AlguiViewDragBar extends AlguiLinearLayout { + + public static final String TAG = "AlguiViewDragBar"; + //占位符 + public static final String PROGRESS_PLACEHOLDER = "{v}";//代表拖动条进度 + + Context aContext; + AlguiFrameLayout dragLayout;//拖动条布局 + SeekBar drag;//拖动条 + GradientDrawable dragBack;//拖动条背景 + GradientDrawable dragFore;//拖动条前景 + GradientDrawable dragSlider;//拖动条滑块 + AlguiViewText dragText;//拖动条文本 + AlguiViewButton minusB;//递减按钮 + AlguiViewButton addB;//递增按钮 + + + int ph=-1;//进度文本高度 + CharSequence valueText="";//进度文本 + int occStart;//进度占位符起始位置 + int occEnd;//进度占位符结束位置 + int __bit__;//小数位数 + int __TuneBit__;//递增递减在哪个小数位 + + //只存储未经转换为整数的虚进度 + double __P__;//当前进度 + double __min__;//最小进度 + double __max__;//最大进度 + + //对外部提供get拓展方法 + public AlguiFrameLayout getByteDragLayout() { + return dragLayout; + } + + public SeekBar getByteDragBar() { + return drag; + } + + public GradientDrawable getByteDragBack() { + return dragBack; + } + + public GradientDrawable getByteDragFore() { + return dragFore; + } + + public GradientDrawable getByteDragSlider() { + return dragSlider; + } + + public AlguiViewText getByteDragText() { + return dragText; + } + + public AlguiViewButton getByteMinusButton() { + return minusB; + } + + public AlguiViewButton getByteAddButton() { + return addB; + } + + + //拖动事件回调反馈 + AlguiCallback.DragBar call; + boolean isInitDrag = false;//是否已经初始化拖动事件 + //初始化内部拖动事件 + private void initDrag() { + //输入框输入文本监听器 + drag.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + //更新double进度 + public double update(int p) { + String vstr=Integer.toString(p); + __P__ = p; + + //对于有小数 + if (__bit__ != 0) { + //将当前进度转换为对应小数位的double + vstr = String.format("%." + __bit__ + "f", int2double(p, -__bit__)); + try { + __P__ = Double.parseDouble(vstr); //保存进度double + } catch (NumberFormatException e) { + dragText.setCatText(vstr + "异常" + ":" + e.getMessage()); + } + } + + //更新文本 + if (occStart >= 0) + dragText.setCatText(new SpannableStringBuilder(valueText).replace(occStart, occEnd, vstr)); + else + dragText.setCatText(valueText + vstr); + //dragText.setCatText("double:" + __P__ + "|int:" + p + "|str:" + vstr); + + return __P__; + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // 当开始拖动拖动条时调用 + update(seekBar.getProgress()); + if (call != null) + call.start(__P__); + } + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + // 当拖动条进度改变时调用 + //将当前进度转换为对应小数位的double + update(progress); + if (call != null) + call.update(__P__); + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // 当停止拖动拖动条时调用 + update(seekBar.getProgress()); + if (call != null) + call.end(__P__); + } + }); + //递减 + minusB.setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + if (call != null) + call.start(__P__); + __P__ -= Math.pow(10, -__TuneBit__); + setCatValue(__P__); + if (call != null) + call.end(__P__); + } + } + ); + + //递增 + addB.setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + if (call != null) + call.start(__P__); + __P__ += Math.pow(10, -__TuneBit__); + setCatValue(__P__); + if (call != null) + call.end(__P__); + } + } + ); + isInitDrag = true; + } + + //设置拖动事件回调反馈接口 + public AlguiViewDragBar setCatCallback(AlguiCallback.DragBar c) { + if (c == null) { + drag.setOnSeekBarChangeListener(null); + minusB.setCatCallback(null); + addB.setCatCallback(null); + isInitDrag = false; + } else { + call = c; + if (!isInitDrag) { + initDrag(); + } + } + return this; + } + + //获取拖动事件回调反馈接口 + public AlguiCallback.DragBar getByteCallback() { + return call; + } + + //核心转换器 + //int和double互转 参数:值,小数位数(例 -3三位小数1变0.001 3转换回整数0.001变1) + public static double int2double(double num, int bit) { + //计算乘积 10的bit次方 + double factor = Math.pow(10, bit); + return num * factor; + } + + + //设置进度小数位数 + public AlguiViewDragBar setCatValueBit(int bit) { + __bit__ = bit; + //更新进度 + setCatValueMax(__max__); + setCatValueMin(__min__); + setCatValue(__P__); + setCatValueTuneBit(__bit__); + return this; + } + //设置在哪个小数位进行递增递减调节 + public AlguiViewDragBar setCatValueTuneBit(int bit) { + if (bit > __bit__) + bit = __bit__; + __TuneBit__ = bit; + return this; + } + //设置进度 + public AlguiViewDragBar setCatValue(double p) { + __P__ = p; + if (__P__ < __min__) + __P__ = __min__; + + if (__P__ > __max__) + __P__ = __max__; + + final int v ; + if (__bit__ != 0) { + v = (int)int2double(__P__, __bit__); + } else { + v = (int)__P__; + } + //必须在UI渲染线程更新进度 否则无法更新进度条进度UI + drag.post(new Runnable() + { + @Override + public void run() { + drag.setProgress(v); + } + }); + return this; + } + //设置最小进度 + public AlguiViewDragBar setCatValueMin(double min) { + __min__ = min; + if (__min__ >= __max__) + //__min__ = __max__ - 1; + //必须先确保最大进度始终比最小进度大再设置最小进度 否则设置会异常丢失一位 + drag.setMax((int)min + 10); + + + if (__bit__ != 0) { + int v = (int)int2double(__min__, __bit__); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)//安卓8以上 + drag.setMin(v); + } else { + int v = (int)__min__; + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)//安卓8以上 + drag.setMin(v); + } + + if (__P__ < __min__) { + setCatValue(__min__); + } + return this; + } + //设置最大进度 + public AlguiViewDragBar setCatValueMax(double max) { + __max__ = max; + if (__max__ <= __min__) + __max__ = __min__ + 1; + + + if (__bit__ != 0) { + int v = (int)int2double(__max__, __bit__); + drag.setMax(v); + } else { + int v=(int)__max__; + drag.setMax(v); + } + if (__P__ > __max__) { + setCatValue(__max__); + } + return this; + } + + //&继承父类方法链 + // 设置大小 + public AlguiViewDragBar setCatSize(float w, float h) { + super.setCatSize(w, h); // 调用父类的方法 + return this; + } + + // 设置权重 + public AlguiViewDragBar setCatWeight(float weight) { + super.setCatWeight(weight); // 调用父类的方法 + return this; + } + + // 设置内边距 + public AlguiViewDragBar setCatPadding(float left, float top, float right, float bottom) { + super.setCatPadding(left, top, right, bottom); // 调用父类的方法 + return this; + } + + // 设置外边距 + public AlguiViewDragBar setCatMargins(float left, float top, float right, float bottom) { + super.setCatMargins(left, top, right, bottom); // 调用父类的方法 + return this; + } + + // 设置圆角半径 + public AlguiViewDragBar setCatRadiu(float radiu) { + super.setCatRadiu(radiu); // 调用父类的方法 + return this; + } + + // 设置描边 + public AlguiViewDragBar setCatBorder(float borderSize, int borderColor) { + super.setCatBorder(borderSize, borderColor); // 调用父类的方法 + return this; + } + + // 设置父布局 + public AlguiViewDragBar setCatParentLayout(ViewGroup vg) { + super.setCatParentLayout(vg); // 调用父类的方法 + return this; + } + + + + + + + //拖动条----- + //设置进度文本 + public AlguiViewDragBar setCatText(CharSequence text, Object... args) { + valueText = text; + //获取进度占位符起始和结束位置 + occStart = text.toString().indexOf(PROGRESS_PLACEHOLDER); + occEnd = occStart + PROGRESS_PLACEHOLDER.length(); + String str =""; + if (__bit__ != 0) + str = String.format("%." + __bit__ + "f", __P__); + else + str = Integer.toString((int)__P__); + + //存在进度占位符时在占位符处补全进度值 + if (occStart >= 0) { + dragText.setCatText(new SpannableStringBuilder(text).replace(occStart, occEnd, str), args); + } else { + dragText.setCatText(text + str, args); + } + return this; + } + + + public AlguiViewDragBar setCatText1(CharSequence text, Object... args) { + valueText = text; + dragText.setCatText(text,args); + + return this; + } + + + //设置文本颜色 + public AlguiViewDragBar setCatTextColor(int... color) { + dragText.setCatTextColor(color); + return this; + } + //设置文本动态渐变效果启动状态 + public AlguiViewDragBar setCatTextMoveGrad(boolean b) { + dragText.setCatTextMoveGrad(b); + return this; + } + //设置文本发光 + public AlguiViewDragBar setCatTextGlow(float radius, int color) { + dragText.setCatTextGlow(radius, color); + return this; + } + //设置文本字体 (Assets文件夹下的字体文件名) + public AlguiViewDragBar setCatTextTFAssets(String assetsTfFileName) { + dragText.setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewDragBar setCatTextTFAssets(String assetsTfFileName, int style) { + dragText.setCatTextTFAssets(assetsTfFileName, style); + return this; + } + // 设置拖动条背景颜色 + public AlguiViewDragBar setCatBackColor(int... backColor) { + if (backColor.length == 1) { + //单个颜色 + dragBack.setColor(backColor[0]); + } else if (backColor.length > 1) { + //多个颜色,使用渐变 + dragBack.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); //渐变方向 + //最后一个元素如果是渐变类型则应用否则默认线性渐变 + if (isGdType(backColor[backColor.length - 1])) { + dragBack.setGradientType(backColor[backColor.length - 1]); + int[] newArray = Arrays.copyOf(backColor, backColor.length - 1);//删除最后一个元素 + dragBack.setColors(newArray);//设置颜色 + } else { + dragBack.setGradientType(GradientDrawable.LINEAR_GRADIENT); + dragBack.setColors(backColor);//设置颜色 + } + } + return this; + } + + // 设置拖动条背景描边 + public AlguiViewDragBar setCatBackBorder(float borderSize, int borderColor) { + dragBack.setStroke((int)dp2px(borderSize), borderColor); + return this; + } + + // 设置拖动条前景颜色 + public AlguiViewDragBar setCatForeColor(int... backColor) { + if (backColor.length == 1) { + //单个颜色 + dragFore.setColor(backColor[0]); + } else if (backColor.length > 1) { + //多个颜色,使用渐变 + dragFore.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); //渐变方向 + //最后一个元素如果是渐变类型则应用否则默认线性渐变 + if (isGdType(backColor[backColor.length - 1])) { + dragFore.setGradientType(backColor[backColor.length - 1]); + int[] newArray = Arrays.copyOf(backColor, backColor.length - 1);//删除最后一个元素 + dragFore.setColors(newArray);//设置颜色 + } else { + dragFore.setGradientType(GradientDrawable.LINEAR_GRADIENT); + dragFore.setColors(backColor);//设置颜色 + } + } + return this; + } + + // 设置拖动条前景描边 + public AlguiViewDragBar setCatForeBorder(float borderSize, int borderColor) { + dragFore.setStroke((int)dp2px(borderSize), borderColor); + return this; + } + + // 设置拖动条滑块颜色 + public AlguiViewDragBar setCatSliderColor(int... backColor) { + if (backColor.length == 1) { + //单个颜色 + dragSlider.setColor(backColor[0]); + } else if (backColor.length > 1) { + //多个颜色,使用渐变 + dragSlider.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); //渐变方向 + //最后一个元素如果是渐变类型则应用否则默认线性渐变 + if (isGdType(backColor[backColor.length - 1])) { + dragSlider.setGradientType(backColor[backColor.length - 1]); + int[] newArray = Arrays.copyOf(backColor, backColor.length - 1);//删除最后一个元素 + dragSlider.setColors(newArray);//设置颜色 + } else { + dragSlider.setGradientType(GradientDrawable.LINEAR_GRADIENT); + dragSlider.setColors(backColor);//设置颜色 + } + } + return this; + } + + // 设置拖动条滑块描边 + public AlguiViewDragBar setCatSliderBorder(float borderSize, int borderColor) { + dragSlider.setStroke((int)dp2px(borderSize), borderColor); + return this; + } + + + + + // 设置按钮点击边框颜色 + public AlguiViewDragBar setCatButtonClickBorderColor(int... backColor) { + super.setCatBackColor(backColor); // 调用父类的方法 + return this; + } + + //设置隐藏递增递减按钮 + public AlguiViewDragBar setCatHideButton(boolean isHideButton) { + if (isHideButton) { + //隐藏 + addB.setVisibility(LinearLayout.GONE); + minusB.setVisibility(LinearLayout.GONE); + } else { + //显示 + addB.setVisibility(LinearLayout.VISIBLE); + minusB.setVisibility(LinearLayout.VISIBLE); + } + return this; + } + + + + + + + //递增按钮----- + + //设置递增按钮背景颜色 + public AlguiViewDragBar setCatAddButtonBackColor(int... backColor) { + addB.setCatBackColor(backColor); + return this; + } + //设置递增按钮描边 + public AlguiViewDragBar setCatAddButtonBorder(float size, int color) { + addB.setCatBorder(size, color); + return this; + } + //设置递增按钮文本 + public AlguiViewDragBar setCatAddButtonText(CharSequence text) { + addB.setCatText(text); + return this; + } + //设置递增按钮文本颜色 + public AlguiViewDragBar setCatAddButtonTextColor(int... color) { + addB.setCatTextColor(color); + return this; + } + //设置递增按钮文本动态渐变效果启动状态 + public AlguiViewDragBar setCatAddButtonTextMoveGrad(boolean b) { + addB.setCatTextMoveGrad(b); + return this; + } + //设置递增按钮文本发光 + public AlguiViewDragBar setCatAddButtonTextGlow(float radius, int color) { + addB.setCatTextGlow(radius, color); + return this; + } + //设置递增按钮文本字体 (Assets文件夹下的字体文件名) + public AlguiViewDragBar setCatAddButtonTextTFAssets(String assetsTfFileName) { + addB.setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewDragBar setCatAddButtonTextTFAssets(String assetsTfFileName, int style) { + addB.setCatTextTFAssets(assetsTfFileName, style); + return this; + } + + + + + + + //递减按钮----- + + //设置递减按钮背景颜色 + public AlguiViewDragBar setCatMinusButtonBackColor(int... backColor) { + minusB.setCatBackColor(backColor); + return this; + } + //设置递减按钮描边 + public AlguiViewDragBar setCatMinusButtonBorder(float size, int color) { + minusB.setCatBorder(size, color); + return this; + } + //设置递减按钮文本 + public AlguiViewDragBar setCatMinusButtonText(CharSequence text) { + minusB.setCatText(text); + return this; + } + //设置递减按钮文本颜色 + public AlguiViewDragBar setCatMinusButtonTextColor(int... color) { + minusB.setCatTextColor(color); + return this; + } + //设置递减按钮文本动态渐变效果启动状态 + public AlguiViewDragBar setCatMinusButtonTextMoveGrad(boolean b) { + minusB.setCatTextMoveGrad(b); + return this; + } + //设置递减按钮文本发光 + public AlguiViewDragBar setCatMinusButtonTextGlow(float radius, int color) { + minusB.setCatTextGlow(radius, color); + return this; + } + //设置递减按钮文本字体 (Assets文件夹下的字体文件名) + public AlguiViewDragBar setCatMinusButtonTextTFAssets(String assetsTfFileName) { + minusB.setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewDragBar setCatMinusButtonTextTFAssets(String assetsTfFileName, int style) { + minusB.setCatTextTFAssets(assetsTfFileName, style); + return this; + } + + public AlguiViewDragBar(Context context) { + super(context); + aContext = context; + init(); + } + + public AlguiViewDragBar(Context context, CharSequence text) { + this(context); + setCatText(text); + } + + //设置所有文本大小 (相对进度文本改变所有子视图大小) + public AlguiViewDragBar setCatTextSize(float size) { + dragText.setCatTextSize(size);//进度文本大小 + minusB.setCatTextSize(size);//递减按钮文本大小 + addB.setCatTextSize(size);//递增按钮文本大小 + //等待文本测量完成才设置拖动条的样式 确保拖动条高度与文本高度一致 + dragText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + //移除监听器以避免重复调用 + //dragText.getViewTreeObserver().removeOnGlobalLayoutListener(this); + //获取文本高度 + int textHeight=dragText.getHeight(); + //只有在文本高度发生改变时才更新 + if (textHeight == ph && ph != -1) + return; + //AlguiLog.d(textHeight + "高"); + //设置拖动条背景大小:宽度拉满高度为文本高度 + dragBack.setSize(AlguiFrameLayout.LayoutParams.MATCH_PARENT, textHeight); + //设置拖动条前景大小:宽度拉满高度为文本高度 + dragFore.setSize(AlguiFrameLayout.LayoutParams.MATCH_PARENT, textHeight); + //设置拖动条滑块大小:宽高为文本高度 确保正方形 + dragSlider.setSize(textHeight, textHeight); + + //设置递减递增按钮宽高为文本高度 确保正方形 + minusB.setLayoutParams(new AlguiLinearLayout.LayoutParams(textHeight, textHeight)); + addB.setLayoutParams(new AlguiLinearLayout.LayoutParams(textHeight, textHeight)); + //应用样式 + drag.setProgressDrawable(new LayerDrawable(new Drawable[]{ + dragBack, + new ClipDrawable(dragFore, Gravity.LEFT, ClipDrawable.HORIZONTAL) + })); + dragText.setMaxLines(2); // 限制文本最多显示2行 + drag.setThumb(dragSlider); + ph = textHeight;//更新文本高度 + } + }); + return this; + } + + + private void init() { + //根布局 + super.setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + super.setCatWeight(1); + super.setCatBackColor(0xFF858585);//将背景颜色作为按钮点击反馈边框颜色 因为按钮有缩放动画 + super.setOrientation(LinearLayout.HORIZONTAL);//横向 + super.setGravity(Gravity.CENTER_VERTICAL);//垂直居中 + + //拖动条布局 + dragLayout = new AlguiFrameLayout(aContext); + dragLayout.setCatSize(AlguiFrameLayout.LayoutParams.MATCH_PARENT, AlguiFrameLayout.LayoutParams.WRAP_CONTENT); + dragLayout.setCatWeight(1); + + //拖动条 + drag = new SeekBar(aContext); + drag.setPadding(0, 0, 0, 0);//确保SeekBar没有内边距 + //安卓9以下没有 + // drag.setMinWidth(0);//确保SeekBar不限制最小宽度 + // drag.setMinHeight(0);//确保SeekBar不限制最小高度 + + //拖动条进度文本 + dragText = new AlguiViewText(aContext); + dragText.setCatPadding(0, 2, 0, 2);//拖动条文本内边距 + + //先添加拖动条 + dragLayout.addView(drag, new AlguiFrameLayout.LayoutParams( + AlguiFrameLayout.LayoutParams.MATCH_PARENT, + AlguiFrameLayout.LayoutParams.WRAP_CONTENT)); + //再往中心叠加文本 + dragLayout.addView(dragText, new AlguiFrameLayout.LayoutParams( + AlguiFrameLayout.LayoutParams.WRAP_CONTENT, + AlguiFrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); + + //递减按钮 + minusB = new AlguiViewButton(aContext, "-"); + minusB.setCatPadding(0, 0, 0, 0);//重置内边距 + + //递增按钮 + addB = new AlguiViewButton(aContext, "+"); + addB.setCatPadding(0, 0, 0, 0);//重置内边距 + + //构造布局 + addView(dragLayout); + addView(minusB); + addView(addB); + + //进度条背景样式 + dragBack = new GradientDrawable(); + dragBack.setShape(GradientDrawable.RECTANGLE); + //进度条前景样式 + dragFore = new GradientDrawable(); + dragFore.setShape(GradientDrawable.RECTANGLE); + //滑块样式 + dragSlider = new GradientDrawable(); + dragSlider.setShape(GradientDrawable.RECTANGLE); + + //默认拖动条颜色 + setCatBackColor(0xFF20324D);//背景颜色 + setCatForeColor(0);//前景颜色 + setCatSliderColor(0xFF3D85E0);//滑块颜色 + + setCatTextSize(7);//初始化所有文本大小 (内部初始化大小后才会应用拖动条样式) + + initDrag();//初始化拖动事件 + + setCatValueBit(0);//默认小数位0 整数 + setCatValueMin(0);//默认最小进度 + setCatValueMax(100);//默认最大进度 + setCatValueTuneBit(0);//默认递增递减小数位 + + setCatText(TAG);//默认进度文本 + } + + + //判断是否为渐变类型 + public static boolean isGdType(int typeIndex) { + return typeIndex == GradientDrawable.LINE || + typeIndex == GradientDrawable.LINEAR_GRADIENT || + typeIndex == GradientDrawable.OVAL || + typeIndex == GradientDrawable.RADIAL_GRADIENT || + typeIndex == GradientDrawable.RECTANGLE || + typeIndex == GradientDrawable.RING || + typeIndex == GradientDrawable.SWEEP_GRADIENT; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewFoldMenu.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewFoldMenu.java new file mode 100644 index 0000000..e0564af --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewFoldMenu.java @@ -0,0 +1,456 @@ +package com.bytecat.algui.AlguiViews; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/10/25 12:15 + * @Describe Algui折叠菜单 + */ +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.Typeface; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiViews.AlguiViewTriangle; +import java.util.ArrayList; +import com.bytecat.algui.AlguiManager.AlguiAssets; + +public class AlguiViewFoldMenu extends AlguiLinearLayout { + + public static final String TAG = "AlguiViewFoldMenu"; + + Context aContext; + AlguiViewItem title;//标题 + AlguiViewTriangle triangleView;//三角形 + AlguiFlowLayout insideLayout;//内部展开布局 + float textSize=-1;//文本大小 (其它视图将参考此大小进行缩放) + + //点击事件回调反馈 + AlguiCallback.Click call; + boolean isUnfold = false;//展开状态 + boolean isEnableUnfold = true;//是否可以展开 + boolean isInitClick=false;//是否已经初始化点击事件 + //初始化内部点击事件 + private void initClick() { + //标题点击事件 + title.setCatCallback(new AlguiCallback.Item() { + @Override + public void item(int id) { + setCatUnfold(!isUnfold); + } + }); + isInitClick = true; + } + //设置点击事件回调反馈接口 + public AlguiViewFoldMenu setCatCallback(AlguiCallback.Click c) { + if (c == null) { + title.setOnClickListener(null); + isInitClick = false; + } else { + call = c; + if (!isInitClick) { + initClick(); + } + } + return this; + } + + //获取点击事件回调反馈接口 + public AlguiCallback.Click getByteCallback() { + return call; + } + //设置默认展开状态 + public AlguiViewFoldMenu setCatUnfold(boolean isUnfold) { + if (isEnableUnfold) { + this.isUnfold = isUnfold; + + if (isUnfold) { + //展开则三角形位于上边 + if (triangleView != null) + triangleView.setCatType(AlguiViewTriangle.Type.EQUILATERAL_TOP); + //内部布局可见 + insideLayout.setVisibility(LinearLayout.VISIBLE); + } else { + //未展开则三角形位于左边 + if (triangleView != null) + triangleView.setCatType(AlguiViewTriangle.Type.EQUILATERAL_LEFT); + //内部布局隐藏 + insideLayout.setVisibility(LinearLayout.GONE); + } + + } + if (call != null) + call.click(isUnfold);//回调 + return this; + } + + //设置是否可以展开 + public AlguiViewFoldMenu setCatEnableUnfold(boolean isEnableUnfold) { + this.isEnableUnfold = isEnableUnfold; + return this; + } + + + /** + * 获取标题 + * @return 标题 + */ + public AlguiViewItem getByteTitleLayout() { + return title; + } + + + /** + * 获取三角形视图 + * @return 三角形视图 + */ + public AlguiViewTriangle getByteTriangleView() { + return triangleView; + } + + + + /** + * 获取内部展开布局 + * @return 内部展开布局 + */ + public AlguiFlowLayout getByteInsideLayout() { + return insideLayout; + } + //获取所有行 + public ArrayList getByteLineList() { + return insideLayout.getByteLineList(); + } + //获取当前行 (最后一行) + public AlguiLinearLayout getByteLine() { + return insideLayout.getByteLine(); + } + //获取指定行 + public AlguiLinearLayout getByteLine(int index) { + return insideLayout.getByteLine(index); + } + + + + public AlguiViewFoldMenu(Context c) { + super(c); + aContext = c; + init(); + } + public AlguiViewFoldMenu(Context c, CharSequence titleText) { + this(c); + setCatText(titleText); + } + + //设置根大小 + public AlguiViewFoldMenu setCatSize(float w, float h) { + super.setCatSize(w, h); + return this; + } + + //设置根权重 + public AlguiViewFoldMenu setCatWeight(float weight) { + super.setCatWeight(weight); + return this; + } + + //设置内边距 + public AlguiViewFoldMenu setCatPadding(float left, float top, float right, float bottom) { + insideLayout.setCatPadding(left, top, right, bottom); + return this; + } + //设置根外边距 + public AlguiViewFoldMenu setCatMargins(float left, float top, float right, float bottom) { + super.setCatMargins(left, top, right, bottom); + return this; + } + //设置根背景颜色 + public AlguiViewFoldMenu setCatBackColor(int... backColor) { + super.setCatBackColor(backColor); + return this; + } + //设置根圆角半径 + public AlguiViewFoldMenu setCatRadiu(float r) { + super.setCatRadiu(r);//圆角 + return this; + } + //设置根描边 + public AlguiViewFoldMenu setCatBorder(float size, int color) { + super.setCatBorder(size, color); + return this; + } + //设置标题背景颜色 + public AlguiViewFoldMenu setCatTitleBackColor(int... backColor) { + title.setCatBackColor(backColor); + return this; + } + //设置标题半径 + public AlguiViewFoldMenu setCatTitleRadiu(float r) { + title.setCatRadiu(r);//圆角 + return this; + } + //设置标题描边 + public AlguiViewFoldMenu setCatTitleBorder(float size, int color) { + title.setCatBorder(size, color); + return this; + } + + //设置图标 + //支持:网络图像链接,base64图像编码,本地图像文件 + //格式:png,jpg,gif… + //注意:设置后将覆盖默认的三角形 设置null为默认三角视图 + public AlguiViewFoldMenu setCatIcon(@Nullable String url_base64_filePath) { + if (url_base64_filePath != null) { + if (triangleView != null) + if (title.indexOfChild(triangleView) > -1) { + title.remView(triangleView); + } + title.setCatIcon(url_base64_filePath); + } else { + //null则设置为三角视图 + title.setCatIcon(null); + if (triangleView == null) { + triangleView = new AlguiViewTriangle(aContext); + triangleView.setCatColor(0xffADB1B7);//三角形颜色 + triangleView.setCatMargins(0,0,7,0); + if (textSize != -1) + triangleView.setCatSize(textSize / 1.2f);//三角形大小 + } + if (title.indexOfChild(triangleView) < 0) + title.addView(triangleView, 0);//标题添加三角形 + } + + return this; + } + //设置三角形颜色 + /*public AlguiCollapse setCatAngleColor(int color) { + triangleView.setColor(color);//颜色 + return this; + }*/ + + //设置图标圆角半径 + public AlguiViewFoldMenu setCatIconRadiu(float r) { + title.setCatIconRadiu(r); + return this; + } + + //设置图标颜色(只能设置单色图像的颜色) + public AlguiViewFoldMenu setCatIconColor(int color) { + title.setCatIconColor(color); + if (triangleView != null) + triangleView.setCatColor(color);//颜色 + return this; + } + + //设置图标透明度 + public AlguiViewFoldMenu setCatIconTransparent(int t) { + title.setCatIconTransparent(t); + return this; + } + + //设置图标毛玻璃模糊 (不支持GIF动态图片模糊) + public AlguiViewFoldMenu setCatIconBlur(int radius) { + title.setCatIconBlur(radius); + return this; + } + //设置标题文本 + public AlguiViewFoldMenu setCatText(CharSequence text, Object... args) { + title.setCatText(text, args); + return this; + } + //设置标题文本颜色 + public AlguiViewFoldMenu setCatTextColor(int... color) { + title.setCatTextColor(color); + return this; + } + //设置文本动态渐变效果启动状态 + public AlguiViewFoldMenu setCatTextMoveGrad(boolean b) { + title.setCatTextMoveGrad(b); + return this; + } + //设置标题文本大小 + public AlguiViewFoldMenu setCatTextSize(float size) { + title.setCatTextSize(size);//标题大小 + if (triangleView != null) + triangleView.setCatSize(size / 1.2f);//三角形大小 + textSize = size; + return this; + } + //设置Assets文件夹字体文件作为标题文本字体 + public AlguiViewFoldMenu setCatTextTFAssets(String assetsTfFileName) { + setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewFoldMenu setCatTextTFAssets(String assetsTfFileName, int style) { + title.setCatTextTFAssets(assetsTfFileName, style); + return this; + } + + //设置内部布局背景颜色 + public AlguiViewFoldMenu setCatInsideBackColor(int... backColor) { + insideLayout.setCatBackColor(backColor); + return this; + } + //设置内部布局半径 + public AlguiViewFoldMenu setCatInsideRadiu(float r) { + insideLayout.setCatRadiu(r);//圆角 + return this; + } + //设置内部布局描边 + public AlguiViewFoldMenu setCatInsideBorder(float size, int color) { + insideLayout.setCatBorder(size, color); + return this; + } + //设置父布局 + public AlguiViewFoldMenu setCatParentLayout(ViewGroup vg) { + if (vg != null) + vg.addView(this); + return this; + } + + //内部流程布局添加视图 中途支持手动换行 + public AlguiViewFoldMenu addView(View... view) { + insideLayout.addView(view); + return this; + } + //设置所有行最大视图数量 自动换行 + public AlguiViewFoldMenu setCatLineMaxView(int num) { + insideLayout.setCatLineMaxView(num); + return this; + } + //设置对话框所有行的外边距 + public AlguiViewFoldMenu setCatLineMargins(float left, float top, float right, float bottom) { + insideLayout.setCatLineMargins(left,top,right,bottom); + return this; + } + //内部布局手动换行 + public AlguiLinearLayout endl() { + return insideLayout.endl(); + } + // 设置内容布局方向 + public AlguiViewFoldMenu setCatOrientation(int orientation) { + if (insideLayout != null) { + insideLayout.setCatOrientation(orientation); + } + return this; + } + +// 删除内容布局所有视图 + public AlguiViewFoldMenu remAllView() { + if (insideLayout != null) { + insideLayout.remAllView(); + } + return this; + } + +// 删除内容布局当前末尾行的子视图 + public AlguiViewFoldMenu remView(View... view) { + if (insideLayout != null) { + insideLayout.remView(view); + } + return this; + } + +// 删除内容布局指定行的视图 + public AlguiViewFoldMenu remViewToLine(int index, View... views) { + if (insideLayout != null) { + insideLayout.remViewToLine(index, views); + } + return this; + } + +// 删除内容布局指定行 (按索引) + public AlguiViewFoldMenu remLine(int... indexs) { + if (insideLayout != null) { + insideLayout.remLine(indexs); + } + return this; + } + +// 删除内容布局指定行 (按对象) + public AlguiViewFoldMenu remLine(AlguiLinearLayout... objs) { + if (insideLayout != null) { + insideLayout.remLine(objs); + } + return this; + } + +// 添加视图到内容布局的指定行 + public AlguiViewFoldMenu addViewToLine(int index, View... views) { + if (insideLayout != null) { + insideLayout.addViewToLine(index, views); + } + return this; + } + + + + //重写添加视图的函数 确保新视图添加到内部布局当中而不是折叠菜单根布局 + @Override + public void addView(View child) { + if (child != null) + insideLayout.addView(child); + } + @Override + public void addView(View child, int index) { + if (child != null) + insideLayout.addView(child, index); + } + @Override + public void addView(View child, int width, int height) { + if (child != null) + insideLayout.addView(child, width, height); + } + //重写后内部往父类添加视图时必须使用此重载 index直接填-1即可 + //原因:其它重载在父类内部会间接最终调用到这个重载 + // 由于重写了所以父类会调用子类重写的重载 + // 那么往父类添加insideLayout时就会无限递归 所以内部必须使用此重装添加 + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + if (child != null) + insideLayout.addView(child, index, params); + } + @Override + public void addView(View child, ViewGroup.LayoutParams params) { + if (child != null) + insideLayout.addView(child, params); + } + + + + //初始化 + private void init() { + + //根布局 + super.setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + super.setCatWeight(1); + setVerticalGravity(16); + setOrientation(LinearLayout.VERTICAL);//垂直 + super.setCatBackColor(0); + + //标题 + title = new AlguiViewItem(aContext); + title.setCatText(TAG); + title.setCatPadding(6, 3, 6, 3); + setCatIcon(null);//添加三角视图 + + setCatTextColor(0xffADB1B7); + setCatTextSize(7); + //内部展开布局 + insideLayout = new AlguiFlowLayout(aContext); + // insideLayout.setVerticalGravity(16); + insideLayout.setCatPadding(3, 2, 3, 2); + //insideLayout.setOrientation(LinearLayout.VERTICAL);//垂直 + + initClick(); + + //所有addView被重写的原因 所以在内部父布局添加布局必须使用三个参数的重载 否则无限递归 + super.addView(title, -1, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + super.addView(insideLayout, -1, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + setCatUnfold(isUnfold);//默认展开状态 + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewImage.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewImage.java new file mode 100644 index 0000000..00bc8d2 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewImage.java @@ -0,0 +1,442 @@ +package com.bytecat.algui.AlguiViews; +import android.annotation.Nullable; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.drawable.AnimatedImageDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.os.Message; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.Toast; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiTools.AlguiToolImage; +import java.io.File; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/11/21 09:00 + * @Describe Algui图像视图 + */ +public class AlguiViewImage extends ImageView { + + public static final String TAG = "AlguiViewImage"; + Context aContext; + LinearLayout.LayoutParams params;//布局参数 + GradientDrawable gradientDrawable;//背景 + Drawable drawable;//原图 + Drawable baseImage_Blur;//模糊后的图像副本 + int blurR = -1;//毛玻璃模糊半径 + float psize = -1;//百分比大小 + int color=0;//图像颜色 + + + //点击事件回调反馈 + AlguiCallback.Click call; + boolean isInitClick=false;//是否已经初始化点击事件 + boolean isChecked=false; + //初始化内部点击事件 + private void initClick() { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + callClick(!isChecked); + } + }); + isInitClick = true; + } + //设置点击事件回调反馈接口 + public AlguiViewImage setCatCallback(AlguiCallback.Click c) { + if (c == null) { + setOnClickListener(null); + isInitClick = false; + } else { + call = c; + if (!isInitClick) { + initClick(); + } + } + return this; + } + + + //获取点击事件回调反馈接口 + public AlguiCallback.Click getByteCallback() { + return call; + } + //代码执行点击事件 + public AlguiViewImage callClick(boolean b) { + isChecked = b; + if (call != null) + call.click(isChecked); + return this; + } + + + // Getter 和 Setter 方法 + + // 获取布局参数 + public LinearLayout.LayoutParams getByteParams() { + return params; + } + + // 获取背景 + public GradientDrawable getByteBack() { + return gradientDrawable; + } + + // 获取图像 + public Drawable getByteDrawable() { + return drawable; + } + + // 设置图像 + public AlguiViewImage setCatDrawable(@Nullable Drawable d) { + this.drawable = d; + setImageDrawable(drawable); + baseImage_Blur = null; + if (drawable != null) { + //自动继承上次大小 + if (psize != -1) + setCatSize(psize); + //自动继承上次的毛玻璃模糊 + if (blurR > 0) + setCatBlur(blurR); + //自动继承上次颜色 + if (color!=0) + setCatColor(color); + //对于gif则开始动画 + + /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + if (drawable instanceof AnimatedImageDrawable) + ((AnimatedImageDrawable) drawable).start();*/ + } else { + __def__(); + } + + return this; + } + + + private void __def__() {setCatImageBase64(AlguiAssets.Icon.image_def);} + private void __deffail__() {setCatImageBase64(AlguiAssets.Icon.image_fail);} + + + public AlguiViewImage(Context c) { + super(c); + aContext = c; + init(); + } + + public AlguiViewImage(Context c, String SetImage_Url_Base64_FilePath) { + this(c); + setCatImage(SetImage_Url_Base64_FilePath); + } + + private void init() { + gradientDrawable = new GradientDrawable(); + setBackground(gradientDrawable); + + params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + setLayoutParams(params); + setClipToOutline(true);//根据父视图轮廓裁剪 + __def__(); + + } + + + + //设置父布局 + public AlguiViewImage setCatParentLayout(ViewGroup vg) { + if (vg != null) + vg.addView(this); + return this; + } + + //设置外边距 + public AlguiViewImage setCatMargins(float left, float top, float right, float bottom) { + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + + //设置权重 + public AlguiViewImage setCatWeight(float weight) { + params.weight = weight; + requestLayout();//重新计算布局 + return this; + } + //设置大小 + public AlguiViewImage setCatSize(float w, float h) { + if ((int)w != ViewGroup.LayoutParams.WRAP_CONTENT + && (int) w != ViewGroup.LayoutParams.MATCH_PARENT + && (int)w != ViewGroup.LayoutParams.FILL_PARENT) { + params.width = (int)dp2px(w); + } else { + params.width = (int)w; + } + + if ((int)h != ViewGroup.LayoutParams.WRAP_CONTENT + && (int)h != ViewGroup.LayoutParams.MATCH_PARENT + && (int)h != ViewGroup.LayoutParams.FILL_PARENT) { + params.height = (int)dp2px(h); + } else { + params.height = (int)h; + } + requestLayout();//重新计算布局 + return this; + } + + + //设置图像大小 (按原始图像尺寸设置百分比大小 1为原始尺寸 作为中心加减延伸) + public AlguiViewImage setCatSize(float percent) { + psize = percent; + if (drawable != null) { + //图像宽高 + int mw = drawable.getIntrinsicWidth(); + int mh = drawable.getIntrinsicHeight(); + + // 根据百分比计算目标宽高 + int newWidth = (int) (mw * percent); + int newHeight = (int) (mh * percent); + + params.width = newWidth; + params.height = newHeight; + requestLayout();//重新计算布局 + } + return this; + } + //设置圆角半径 + public AlguiViewImage setCatRadiu(float r) { + gradientDrawable.setCornerRadius(dp2px(r)); + return this; + } + + +// 设置图像颜色(只能设置单色图像的颜色) + public AlguiViewImage setCatColor(int color) { + this.color = color; + // 不支持动态图 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + if (drawable instanceof AnimatedImageDrawable) { + return this; + } + + Bitmap bitmap = AlguiToolImage.drawableToBitmap(drawable); + if (bitmap != null) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + // 基准颜色 + int R = -1, G = -1, B = -1, A = -1; + // 容忍度的平方 + int toleranceSquared = 50 * 50; + + // 获取所有像素数据 + int[] pixels = new int[w * h]; + bitmap.getPixels(pixels, 0, w, 0, 0, w, h); + + for (int i = 0; i < pixels.length; i++) { + int pixelColor = pixels[i]; + int r = Color.red(pixelColor); + int g = Color.green(pixelColor); + int b = Color.blue(pixelColor); + int a = Color.alpha(pixelColor); + + if (R == -1) { + // 获取第一个不透明颜色用于之后其他颜色对比 + if (a > 0 && (r > 0 || g > 0 || b > 0)) { + R = r; + G = g; + B = b; + A = a; + } + } else { + if (a > 0) { + // 计算颜色差异的平方和 + int rDiff = R - r; + int gDiff = G - g; + int bDiff = B - b; + int colorDiffSquared = rDiff * rDiff + gDiff * gDiff + bDiff * bDiff; + + // 如果颜色差异超过容忍度,说明是多彩图像 + if (colorDiffSquared > toleranceSquared) { + setColorFilter(0); // 多彩图像不做处理 + return this; + } + } + } + } + + // 如果所有像素颜色相同或差异在容忍度范围内,说明是纯色图像 + setColorFilter(color); + } + + return this; + } + + + + + + + //设置图片透明度 + public AlguiViewImage setCatTransparent(int t) { + setAlpha(t); + return this; + } + + //设置毛玻璃模糊 (不支持GIF动态图片模糊) + public AlguiViewImage setCatBlur(int radius) { + blurR = radius;//保存模糊半径,下次改变图片时自动继承这个模糊半径 + //对当前图像进行模糊图像处理 + Drawable d =AlguiToolImage.psImageBlur(drawable, radius, aContext); + if (d != null) { + //设置模糊后的图像 + setImageDrawable(d); + baseImage_Blur = d; + } else { + __deffail__(); + } + + return this; + } + + //设置图像 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiViewImage setCatImage(String Url_Base64_FilePath) { + if (Url_Base64_FilePath != null) { + //字符串开头是http或https则设置为网络图片 + if (Url_Base64_FilePath.startsWith("http://") || Url_Base64_FilePath.startsWith("https://")) { + setCatImageURL(Url_Base64_FilePath); + //对于base64图像检测长度 + } else if (Url_Base64_FilePath.length() > 32 + 16) { + setCatImageBase64(Url_Base64_FilePath); + //其它情况默认识别为本地图像文件 + } else { + setCatImageFile(Url_Base64_FilePath); + } + } else { + __def__(); + } + return this; + } + + //设置网络图像 + public AlguiViewImage setCatImageURL(final String url) { + if (url != null) { + AlguiToolImage.getImageURL(url, new AlguiCallback.Web(){ + @Override + public void web(Message msg) { + switch (msg.what) { + case 200: + Object obj = msg.obj; + if (obj != null) { + if (obj instanceof Drawable) { + setCatDrawable((Drawable)msg.obj); + } + } + break; + case 404: + __deffail__(); + Toast.makeText(getContext(), "网络图片加载失败:服务器发生错误", Toast.LENGTH_SHORT).show(); + break; + case 651: + __deffail__(); + Toast.makeText(getContext(), "网络图片加载失败:图片异常", Toast.LENGTH_SHORT).show(); + break; + } + } + } + ); + } else { + __def__(); + } + + return this; + } + + + //设置本地图像 + //1.可以传入 本地文件路径 例如:/data/user/0/com.bytecat.algui/cache/image.png + //注意:本地文件路径别人手机上没有这个图片,所以这只针对于从网络下载图像到本地,然后引用此下载好的图像 + //2.可以传入 图像文件名 自动在Assets文件夹下搜索此图像文件 + //3.可以传入 项目根目录Assets路径 例如:/assets/image.png + public AlguiViewImage setCatImageFile(String filePath) { + if (filePath != null) { + Drawable d=AlguiToolImage.getImageFile(filePath, aContext); + if (d != null) { + setCatDrawable(d); + } else { + __deffail__(); + } + } else { + __def__(); + } + return this; + } + + + //设置Base64图像 + //对Base64长度有限制,太大可能出现异常 + public AlguiViewImage setCatImageBase64(String base64String) { + if (base64String != null) { + Drawable d=AlguiToolImage.getImageBase64(base64String); + if (d != null) { + setCatDrawable(d); + } else { + __deffail__(); + } + } else { + __def__(); + } + return this; + } + + + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + + + //下载图像到本地 传入路径 例/storage/emulated/0/myapp/images/image.png + //如果单传文件名或无法访问的目录将默认下载到相册 + public File downloadImage(String path) { + if (drawable == null || path == null) { + return null; + } + //如果已经模糊了则保存模糊后的图像副本 否则原图 + return AlguiToolImage.saveDrawableToFile(aContext, baseImage_Blur != null ?baseImage_Blur: drawable, path); + } + + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewInputBox.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewInputBox.java new file mode 100644 index 0000000..c1a1a3d --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewInputBox.java @@ -0,0 +1,554 @@ +package com.bytecat.algui.AlguiViews; +import android.annotation.Nullable; +import android.content.ClipData; +import android.content.ClipDescription; +import android.content.ClipboardManager; +import android.content.Context; +import android.graphics.Typeface; +import android.text.Editable; +import android.text.InputType; +import android.text.Selection; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import com.bytecat.algui.AlguiManager.AlguiCallback; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/12 19:59 + * @Describe 输入框 + */ +public class AlguiViewInputBox extends AlguiLinearLayout { + + public static final String TAG = "AlguiViewInputBox"; + Context aContext; + AlguiViewImage icon;//图标 + EditText editext;//输入框 + AlguiViewButton button;//按钮 + String __Text__="";//输入的文本 + float textSize=-1;//文本大小 + + + // 获取图标(AlguiImage) + public AlguiViewImage getByteIcon() { + return icon; + } + + // 获取输入框(EditText) + public EditText getByteEditText() { + return editext; + } + + // 获取按钮(AlguiButton) + public AlguiViewButton getByteButton() { + return button; + } + + // 获取输入的文本 (String) + public String getByteInputText() { + return __Text__; + } + + //输入事件回调反馈 + AlguiCallback.Input call; + boolean isInitInput = false;//是否已经初始化输入事件 + //初始化内部输入事件 + private void initInput() { + //输入框输入文本监听器 + editext.addTextChangedListener + ( + new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { + // 在文本变化之前执行的操作 + + if (charSequence != null) { + __Text__ = charSequence.toString(); + if (__Text__ == null) + __Text__ = ""; + } else { + __Text__ = ""; + } + + if (call != null) + call.start(__Text__); + + + } + @Override + public void onTextChanged(CharSequence charSequence, int start, int before, int count) { + // 在文本变化时执行的操作 + + if (charSequence != null) { + __Text__ = charSequence.toString(); + if (__Text__ == null) + __Text__ = ""; + } else { + __Text__ = ""; + } + + if (call != null) + call.update(__Text__); + + } + @Override + public void afterTextChanged(Editable editable) { + // 在文本变化之后执行的操作 + + if (editable != null) { + __Text__ = editable.toString(); + if (__Text__ == null) + __Text__ = ""; + } else { + __Text__ = ""; + } + + if (call != null) { + call.end(__Text__); + } + } + } + ); + //按钮点击事件 + button.setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + if (call != null) + call.buttonClick(__Text__); + } + } + ); + + isInitInput = true; + } + + //设置点击事件回调反馈接口 + public AlguiViewInputBox setCatCallback(AlguiCallback.Input c) { + if (c == null) { + editext.addTextChangedListener(null); + button.setCatCallback(null); + isInitInput = false; + } else { + call = c; + if (!isInitInput) { + initInput(); + } + } + return this; + } + + //获取点击事件回调反馈接口 + public AlguiCallback.Input getByteCallback() { + return call; + } + //代码执行按钮点击事件 + public AlguiViewInputBox callButtonClick() { + if (call != null) + call.buttonClick(__Text__); + return this; + } + + + + //&继承父类方法链 + // 设置大小 + public AlguiViewInputBox setCatSize(float w, float h) { + super.setCatSize(w, h); // 调用父类的方法 + return this; + } + + // 设置权重 + public AlguiViewInputBox setCatWeight(float weight) { + super.setCatWeight(weight); // 调用父类的方法 + return this; + } + + // 设置内边距 + public AlguiViewInputBox setCatPadding(float left, float top, float right, float bottom) { + super.setCatPadding(left, top, right, bottom); // 调用父类的方法 + return this; + } + + // 设置外边距 + public AlguiViewInputBox setCatMargins(float left, float top, float right, float bottom) { + super.setCatMargins(left, top, right, bottom); // 调用父类的方法 + return this; + } + + // 设置背景颜色 + public AlguiViewInputBox setCatBackColor(int... backColor) { + super.setCatBackColor(backColor); // 调用父类的方法 + return this; + } + + // 设置圆角半径 + public AlguiViewInputBox setCatRadiu(float radiu) { + super.setCatRadiu(radiu); // 调用父类的方法 + return this; + } + + // 设置描边 + public AlguiViewInputBox setCatBorder(float borderSize, int borderColor) { + super.setCatBorder(borderSize, borderColor); // 调用父类的方法 + return this; + } + + // 设置父布局 + public AlguiViewInputBox setCatParentLayout(ViewGroup vg) { + super.setCatParentLayout(vg); // 调用父类的方法 + return this; + } + + + + + + //设置所有文本大小 + public AlguiViewInputBox setCatTextSize(float size) { + if (editext != null) + editext.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(size));//输入框文本大小 + if (button != null) + button.setCatTextSize(size);//按钮文本大小 + if (icon != null) + icon.setCatSize(size, size);//图标大小 + textSize = size; + return this; + } + //设置所有文本字体 (传入assets文件夹下的字体文件名) + public AlguiViewInputBox setCatTextTFAssets(String assetsTfFileName) { + setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewInputBox setCatTextTFAssets(String assetsTfFileName, int style) { + //设置输入框字体 + editext.setTypeface( + assetsTfFileName != null ? + Typeface.createFromAsset(aContext.getAssets(), assetsTfFileName) + : null, style); + button.setCatTextTFAssets(assetsTfFileName, style);//设置按钮文本字体 + return this; + } + + + + + + + //设置图标 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiViewInputBox setCatIcon(@Nullable String Url_Base64_FilePath) { + if (Url_Base64_FilePath != null) { + if (icon == null) { + icon = new AlguiViewImage(aContext); + icon.setCatMargins(4, 0, 0, 0); + if (textSize != -1) + icon.setCatSize(textSize, textSize); + } + icon.setCatImage(Url_Base64_FilePath); + + if (indexOfChild(icon) < 0) + addView(icon, 0); + } else { + //删除图标 + if (icon != null) + if (indexOfChild(icon) > -1) { + remView(icon); + } + } + return this; + } + + //设置图标颜色 (只支持单色图标) + public AlguiViewInputBox setCatIconColor(int color) { + if (icon != null) + icon.setCatColor(color); + return this; + } + + //设置图标圆角半径 + public AlguiViewInputBox setCatIconRadiu(float r) { + if (icon != null) + icon.setCatRadiu(r); + return this; + } + + + //设置图标透明度 + public AlguiViewInputBox setCatIconTransparent(int t) { + if (icon != null) + icon.setCatTransparent(t); + return this; + } + + //设置图标毛玻璃模糊 (不支持GIF动态图片模糊) + public AlguiViewInputBox setCatIconBlur(int radius) { + if (icon != null) + icon.setCatBlur(radius); + return this; + } + + + + + +//输入类型: +// TYPE_CLASS_TEXT - 用于普通文本输入。适用于大多数文本输入框,显示常规的字符输入键盘。 +// TYPE_TEXT_VARIATION_PASSWORD - 用于密码输入。输入内容会以星号(或其他符号)隐藏,适用于密码输入框。 +// TYPE_TEXT_VARIATION_VISIBLE_PASSWORD - 用于可见密码输入。输入的内容以明文显示,适用于用户希望查看密码的场景。 +// TYPE_TEXT_VARIATION_WEB_PASSWORD - 用于网页密码输入。常用于网页表单中的密码字段,通常有特定的密码管理优化。 +// TYPE_TEXT_VARIATION_URI - 用于URI输入。适用于输入网址或URI(如:http://或ftp://)。 +// TYPE_TEXT_VARIATION_EMAIL_ADDRESS - 用于电子邮件地址输入。键盘会优化为适合输入电子邮件地址,如自动补充 `@` 符号。 +// TYPE_TEXT_VARIATION_PERSON_NAME - 用于输入人名。通常显示优化的人名键盘,便于用户输入全名、姓氏等。 +// TYPE_TEXT_VARIATION_LONG_MESSAGE - 用于输入较长的文本消息。通常会启用多行输入框,并显示“换行”键。 +// TYPE_CLASS_NUMBER - 用于数字输入。显示数字键盘,适合输入价格、数量等数字信息。 +// TYPE_NUMBER_VARIATION_NORMAL - 用于常规数字输入。适合输入数字,没有密码或特殊格式要求。 +// TYPE_NUMBER_VARIATION_PASSWORD - 用于数字密码输入。适用于需要输入数字密码的场景,输入内容会隐藏。 +// TYPE_CLASS_PHONE - 用于电话号码输入。显示专用的电话号码键盘,优化了电话号码输入的格式。 +// TYPE_CLASS_DATETIME - 用于日期或时间输入。显示适合选择日期或时间的键盘。 +// TYPE_TEXT_FLAG_NO_SUGGESTIONS - 禁用文本建议。输入框不会显示任何自动补全或预测文本建议。 +// TYPE_TEXT_FLAG_AUTO_COMPLETE - 启用自动完成功能。通常用于输入电子邮件地址、URL、用户名等,系统会提供自动完成的建议。 +// TYPE_TEXT_FLAG_CAP_CHARACTERS - 强制所有输入字符为大写。输入的每个字母都会自动转为大写。 +// TYPE_TEXT_FLAG_CAP_SENTENCES - 自动将每个句子的首字母转换为大写。适用于正常文本输入。 +// TYPE_TEXT_FLAG_CAP_WORDS - 自动将每个单词的首字母转换为大写。常用于标题或专有名词的输入。 +// TYPE_TEXT_FLAG_MULTI_LINE - 启用多行输入。允许输入换行符,适合需要输入长文本(如评论、消息等)的场景。 + //设置输入类型 + public AlguiViewInputBox setCatInputType(int type) { + editext.setInputType(type); + return this; + } + //设置输入框提示 + public AlguiViewInputBox setCatInputHint(CharSequence text) { + if (text == null) + text = ""; + editext.setHint(text); + return this; + } + //设置输入框提示颜色 + public AlguiViewInputBox setCatInputHintColor(int color) { + editext.setHintTextColor(color); + return this; + } + //设置输入框输入内容 (会触发输入事件) + public AlguiViewInputBox setCatInputText(CharSequence text) { + if (text == null) + text = ""; + editext.setText(text); + __Text__=text.toString(); + return this; + } + //设置输入框输入内容颜色 + public AlguiViewInputBox setCatInputTextColor(int color) { + editext.setTextColor(color); + return this; + } + + + + + + + + + + + + //设置按钮背景颜色 + public AlguiViewInputBox setCatButtonBackColor(int... backColor) { + button.setCatBackColor(backColor); + return this; + } + //设置按钮圆角半径 + public AlguiViewInputBox setCatButtonRadiu(float r) { + button.setCatRadiu(r); + return this; + } + //设置按钮描边 + public AlguiViewInputBox setCatButtonBorder(float size, int color) { + button.setCatBorder(size, color); + return this; + } + //设置按钮文本 + public AlguiViewInputBox setCatButtonText(CharSequence text) { + if(text!=null){ + button.setVisibility(LinearLayout.VISIBLE); + button.setCatText(text); + }else{ + button.setVisibility(LinearLayout.GONE); + } + return this; + } + //设置按钮文本颜色 + public AlguiViewInputBox setCatButtonTextColor(int... color) { + button.setCatTextColor(color); + return this; + } + //设置按钮文本动态渐变效果启动状态 + public AlguiViewInputBox setCatButtonTextMoveGrad(boolean b) { + button.setCatTextMoveGrad(b); + return this; + } + //设置按钮文本发光效果 + public AlguiViewInputBox setCatButtonTextGlow(float radius, int color) { + button.setCatTextGlow(radius, color); + return this; + } + + + + + + + public AlguiViewInputBox(Context context) { + super(context); + aContext = context; + init(); + } + private void init() { + super.setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + super.setCatWeight(1); + super.setCatBackColor(0xff20324D); + super.setOrientation(LinearLayout.HORIZONTAL);//横向 + super.setGravity(Gravity.CENTER_VERTICAL);//垂直居中 + + + //输入框 + LinearLayout.LayoutParams editLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT, 1); + + editext = new EditText(aContext); + editext.setTextIsSelectable(true);//启用输入框文本选择功能 + //设置内容过多时光标拖动时查看之前输入的内容是横向的 + //editext.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE); //设置内容只有单行 + //editext.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD); // 按钮点击事件 + // editext.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME); + editext.setLayoutParams(editLayoutParams); + + editext.setHint(TAG);//设置输入框提示 + editext.setHintTextColor(0xffADB1B7);//提示颜色 + editext.setTextColor(0xC200FF00);//输入内容颜色 + + int padding =(int)dp2px(3); + editext.setPadding(padding, padding, padding, padding);//覆盖输入框原来的内边距 + editext.setBackground(null);//设置一个空背景来覆盖默认输入框的线条 + + button = new AlguiViewButton(aContext, "确定"); + button.setCatSize(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT); + + setCatTextSize(7);//设置文本大小 + + addView(editext); + addView(button); + + // 设置长按监听器 + editext.setOnLongClickListener(new View.OnLongClickListener() { + + AlguiFlowLayout layout; + AlguiViewButton selectAll; + AlguiViewButton copy; + AlguiViewButton paste; + AlguiViewButton shearing; + PopupWindow popupWindow; + boolean isInit=false; + //检查是否正在全选 + private boolean isTextSelectedAll() { + int start = Selection.getSelectionStart(editext.getText()); + int end = Selection.getSelectionEnd(editext.getText()); + + // 判断是否全选 + return start == 0 && end == editext.getText().length(); + } + @Override + public boolean onLongClick(View v) { + + if (!isInit) { + //流式布局 + layout = new AlguiFlowLayout(aContext); + layout.setCatBackColor(0xff505050);//设置布局背景色 让按钮缩放动画后显示此颜色营造按钮按下后描边效果 + + selectAll = new AlguiViewButton(aContext, "全选") + .setCatBackColor(0xff2C2C2E) + .setCatParentLayout(layout) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + editext.selectAll(); + } + } + ); + copy = new AlguiViewButton(aContext, "复制") + .setCatBackColor(0xff2C2C2E) + .setCatParentLayout(layout) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + ClipboardManager clipboardManager = (ClipboardManager) aContext.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = ClipData.newPlainText("text", editext.getText()); + clipboardManager.setPrimaryClip(clipData); + } + } + ); + paste = new AlguiViewButton(aContext, "粘贴") + .setCatBackColor(0xff2C2C2E) + .setCatParentLayout(layout) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + ClipboardManager clipboardManager = (ClipboardManager) aContext.getSystemService(Context.CLIPBOARD_SERVICE); + if (clipboardManager.hasPrimaryClip() && clipboardManager.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { + //如果是全选则清除所有文本 + if (isTextSelectedAll()) + editext.setText(""); + ClipData.Item cItem = clipboardManager.getPrimaryClip().getItemAt(0); + String pasteText = cItem.getText().toString(); + //将粘贴的文本插入到输入框中 + editext.getText().insert(editext.getSelectionStart(), pasteText); + } + } + } + ); + shearing = new AlguiViewButton(aContext, "剪切") + .setCatBackColor(0xff2C2C2E) + .setCatParentLayout(layout) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + ClipboardManager clipboardManager = (ClipboardManager) aContext.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = ClipData.newPlainText("text", editext.getText()); + clipboardManager.setPrimaryClip(clipData);//先复制文本 + editext.setText(""); //清除输入框文本 + } + } + ); + //创建弹窗 + popupWindow = new PopupWindow(layout, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + //popupWindow.setFocusable(true);//设置焦点 + popupWindow.setOutsideTouchable(true);//设置点击外部是否销毁 + isInit = true; + } + //让按钮跟随输入框大小 + float size = textSize; + if (size < 0) + size = 7; + selectAll.setCatTextSize(size); + copy.setCatTextSize(size); + paste.setCatTextSize(size); + shearing.setCatTextSize(size); + + popupWindow.showAsDropDown(v, 0, 0, Gravity.LEFT);//显示弹窗 + + return false;//不要返回true否则影响输入框长按选择文本 + } + }); + + + + + + + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewItem.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewItem.java new file mode 100644 index 0000000..bedca9c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewItem.java @@ -0,0 +1,497 @@ +package com.bytecat.algui.AlguiViews; +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.Typeface; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import java.util.ArrayList; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/12 15:21 + * @Describe Algui 选项按钮 + */ +public class AlguiViewItem extends AlguiLinearLayout { + + public static final String TAG = "AlguiViewItem"; + Context aContext; + int id; + + public void setCatSelectItem() { + }//标识符ID + public AlguiViewItem setCatId(int id) {this.id = id;return this;}//设置标识符ID + public int getByteId() {return id;}//获取标识符ID + + AlguiViewImage icon;//图标 + AlguiViewText text;//文本 + AlguiLinearLayout itemLayout;//选项布局 + float iconSize=-1;//图标大小 + int[] backColors,textColors;//背景和文本颜色 + float strokeSize=-1;//描边大小 + int strokeColor=-1;//描边颜色 + boolean isInside;//开始内部更新 + + //全局 + private static final ArrayList ItemList = new ArrayList<>();//所有项列表 + private static AlguiViewItem selectItem;//当前选中的项 + private static int[] clickBackColors={0xFF397CCD};//项点击后的背景颜色 + private static int[] clickTextColors={0xFFFFFFFF};//项点击后的文本颜色 + private static float clickStrokeSize;//项点击后的描边大小 + private static int clickStrokeColor;//项点击后的描边颜色 + //设置项选中后的背景颜色 + public static void setCatSelectBackColor(int... colors) { + clickBackColors = colors; + } + //设置项选中后的文本颜色 + public static void setCatSelectTextColor(int... colors) { + clickTextColors = colors; + } + //设置项选中后的描边 + public static void setCatSelectBorderColor(float size, int color) { + clickStrokeSize = size; + clickStrokeColor = color; + } + //设置选中项 + public static void setCatSelectItem(AlguiViewItem item) { + if (item != null) + item.select(); + } + public static int[] getByteClickBackColors() { return clickBackColors; } + public static int[] getByteClickTextColors() { return clickTextColors; } + public static float getByteClickStrokeSize() { return clickStrokeSize; } + public static int getByteClickStrokeColor() { return clickStrokeColor; } + + // 获取全局所有项对象的列表 + public static ArrayList getByteStaticItemList() { return ItemList; } + // 获取当前选中的项 + public static AlguiViewItem getByteSelectItem() { return selectItem; } + + //选中 + public AlguiViewItem select() { + selectItem = this;//当前选中项为自身 + //存在点击样式则还原其它项的样式 + if ((clickBackColors != null&&clickBackColors.length>0) || + (clickTextColors != null&&clickTextColors.length>0) || + (clickStrokeSize > 0 && clickStrokeColor > 0) + ) { + for (final AlguiViewItem u:ItemList) { + if (u != null) { + int[] backColors = u.getByteBackColors(); + int[] textColors=u.getByteTextColors(); + float strokeSize = u.getByteBorderSize(); + int strokeColor = u.getByteBorderColor(); + if (backColors != null) + u.setCatBackColor(backColors); + if (textColors != null) { + //恢复文本选项的颜色 + for (Item i:u.getByteItems()) { + if (i != null) { + View v = i.view; + if (v != null) { + if (v instanceof AlguiViewText) { + AlguiViewText aText=(AlguiViewText)v; + aText.setCatTextColor(aText.getByteStyleTextColos()); + } + } + } + } + u.setCatTextColor(textColors); + } + + if (strokeColor != -1 || strokeSize != -1) + u.setCatBorder(strokeSize, strokeColor); + } + } + } + isInside = true;//开始内部更新 + //设置当前项的点击样式 (这里不要使用给外部的方法) + if (clickBackColors != null&&clickTextColors.length>0) + setCatBackColor(clickBackColors); + if (clickTextColors != null&&clickTextColors.length>0) { + //设置选项的颜色 + for (Item i:items) { + if (i != null) { + View v = i.view; + if (v != null) { + if (v instanceof AlguiViewText) { + AlguiViewText aText=(AlguiViewText)v; + aText.setTemStyle(true);//开始临时修改样式 + aText.setCatTextColor(clickTextColors); + aText.setTemStyle(false);//结束临时修改样式 + } + } + } + } + setCatTextColor(clickTextColors); + } + if (clickStrokeSize > 0 && clickStrokeColor > 0) + setCatBorder(clickStrokeSize, clickStrokeColor); + isInside = false;//结束内部更新 + return this; + } + + + // 对于自定义拓展 + // 获取背景颜色 + public int[] getByteBackColors() { return backColors; } + // 获取文本颜色 + public int[] getByteTextColors() { return textColors; } + // 获取描边大小 + public float getByteBorderSize() { return strokeSize; } + // 获取描边颜色 + public int getByteBorderColor() { return strokeColor; } + // 获取图标 + public AlguiViewImage getByteIcon() {return icon;} + // 获取文本 + public AlguiViewText getByteText() {return text;} + // 获取选项布局 + public AlguiLinearLayout getByteItemLayout() { return itemLayout; } + // 获取全局选项列表 + public ArrayList getByteItems() { return items; } + + + //选项结构 + public class Item { + int id; + View view; + Item(int id, View view) { + this.id = id; + this.view = view; + } + } + //添加选项 + public AlguiViewItem addItem(int id, View view) { + if (view != null) { + if (view instanceof AlguiViewText) { + //如果是文本默认跟随标题 + AlguiViewText o=(AlguiViewText) view; + o.setCatTextSize(text.getByteStyleTextSize()); + o.setCatTextColor(text.getByteStyleTextColos()); + } + items.add(new Item(id, view)); + //第一次添加选项默认选中第一个选项 + if (selectItemID == -335348460) { + selectItemID = id; + setCatSwitchItem(selectItemID); + } + } + return this; + } + //添加一些选项 id根据添加顺序自动赋值 0开始 + public AlguiViewItem addItem(View... view) { + int i=0; + for(View v:view){ + if(v!=null){ + addItem(i,v); + i++; + } + } + return this; + } + //切换选项监听 + ArrayList items = new ArrayList<>();//选项列表 + int selectItemID=-335348460;//当前选中选项ID + boolean isEnableSwitch=true;// 是否启用切换选项功能 + AlguiCallback.Item call; + boolean isInitClick=false;//是否已经初始化点击事件 + //初始化内部点击事件 + private void initClick() { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + select();//更新选中样式 + if (isEnableSwitch) { + //查找下一个选项 + for (int i = 0; i < items.size(); i++) { + Item item = items.get(i); + //找到当前选项 + if (item.id == selectItemID) { + //将当前选项改为下一个选项 + int nextIndex = i + 1; + //如果是最后一个选项则为第一个选项 + if (nextIndex >= items.size()) { + nextIndex = 0; + } + selectItemID = items.get(nextIndex).id; + break; + } + + } + setCatSwitchItem(selectItemID);//设置切换到下一个选项 + + } + + } + }); + isInitClick = true; + } + //设置选项事件回调反馈接口 + public AlguiViewItem setCatCallback(AlguiCallback.Item c) { + if (c == null) { + setOnClickListener(null); + isInitClick = false; + } else { + call = c; + if (!isInitClick) { + initClick(); + } + } + return this; + } + //获取选项事件回调反馈接口 + public AlguiCallback.Item getByteCallback() { + return call; + } + //设置切换选项 + public AlguiViewItem setCatSwitchItem(int selectItemID) { + View v=null; + for (Item i:items) { + if (i != null) { + if (i.id == selectItemID) { + v = i.view; + break; + } + } + } + if (v != null) { + this.selectItemID = selectItemID; + itemLayout.remAllView(); + itemLayout.addView(v); + } + if (call != null) + call.item(selectItemID);//回调切换选项 + return this; + } + //设置是否启用切换 + public AlguiViewItem setCatEnableSwitch(boolean isEnableSwitch) { + this.isEnableSwitch = isEnableSwitch; + return this; + } + + + + + //&继承父类方法链 + // 设置大小 + public AlguiViewItem setCatSize(float w, float h) { + super.setCatSize(w, h); // 调用父类的方法 + return this; + } + + // 设置权重 + public AlguiViewItem setCatWeight(float weight) { + super.setCatWeight(weight); // 调用父类的方法 + return this; + } + + // 设置内边距 + public AlguiViewItem setCatPadding(float left, float top, float right, float bottom) { + super.setCatPadding(left, top, right, bottom); // 调用父类的方法 + return this; + } + + // 设置外边距 + public AlguiViewItem setCatMargins(float left, float top, float right, float bottom) { + super.setCatMargins(left, top, right, bottom); // 调用父类的方法 + return this; + } + + // 设置背景颜色 + public AlguiViewItem setCatBackColor(int... backColor) { + if (!isInside) + backColors = backColor; + super.setCatBackColor(backColor); // 调用父类的方法 + return this; + } + + // 设置圆角半径 + public AlguiViewItem setCatRadiu(float radiu) { + super.setCatRadiu(radiu); // 调用父类的方法 + return this; + } + + // 设置描边 + public AlguiViewItem setCatBorder(float borderSize, int borderColor) { + if (!isInside) { + strokeSize = borderSize; + strokeColor = borderColor; + } + super.setCatBorder(borderSize, borderColor); // 调用父类的方法 + return this; + } + + // 设置父布局 + public AlguiViewItem setCatParentLayout(ViewGroup vg) { + super.setCatParentLayout(vg); // 调用父类的方法 + return this; + } + + //设置文本 + public AlguiViewItem setCatText(CharSequence textstr, Object... args) { + this.text.setCatText(textstr, args); + return this; + } + + //设置文本颜色 + public AlguiViewItem setCatTextColor(int... color) { + if (!isInside) + textColors = color; + text.setCatTextColor(color); + for(Item i:items){ + if(i==null) + continue; + View iv=i.view; + if(iv==null) + continue; + if (iv instanceof AlguiViewText) { + //如果是文本跟随标题 + AlguiViewText o=(AlguiViewText) iv; + + o.setCatTextColor(color); + } + } + + return this; + } + //设置文本动态渐变效果启动状态 + public AlguiViewItem setCatTextMoveGrad(boolean b) { + text.setCatTextMoveGrad(b); + return this; + } + //设置文本发光 + public AlguiViewItem setCatTextGlow(float radius, int color) { + text.setCatTextGlow(radius, color); + return this; + } + + //设置文本字体 (Assets文件夹下的字体文件名) + public AlguiViewItem setCatTextTFAssets(String assetsTfFileName) { + text.setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewItem setCatTextTFAssets(String assetsTfFileName, int style) { + text.setCatTextTFAssets(assetsTfFileName, style); + return this; + } + //设置文本大小 + public AlguiViewItem setCatTextSize(float size) { + text.setCatTextSize(size);//设置文本大小 + iconSize = size * 1.3f;//图标是文本的0.3倍 + if (icon != null) + icon.setCatSize(iconSize, iconSize); + for(Item i:items){ + if(i==null) + continue; + View iv=i.view; + if(iv==null) + continue; + if (iv instanceof AlguiViewText) { + //如果是文本跟随标题 + AlguiViewText o=(AlguiViewText) iv; + o.setCatTextSize(size); + } + } + return this; + } + //设置图标 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiViewItem setCatIcon(@Nullable String Url_Base64_FilePath) { + if (Url_Base64_FilePath != null) { + if (icon == null) { + icon = new AlguiViewImage(aContext); + icon.setCatMargins(0, 0, 5, 0); + if (iconSize != -1) + icon.setCatSize(iconSize, iconSize); + } + icon.setCatImage(Url_Base64_FilePath); + + if (indexOfChild(icon) < 0) + addView(icon, 0); + } else { + //删除图标 + if (icon != null) + if (indexOfChild(icon) > -1) { + remView(icon); + } + } + return this; + } + //设置图标颜色 (只支持单色图标) + public AlguiViewItem setCatIconColor(int color) { + if (icon != null) + icon.setCatColor(color); + return this; + } + + //设置图标圆角半径 + public AlguiViewItem setCatIconRadiu(float r) { + if (icon != null) + icon.setCatRadiu(r); + return this; + } + + + //设置图标透明度 + public AlguiViewItem setCatIconTransparent(int t) { + if (icon != null) + icon.setCatTransparent(t); + return this; + } + + //设置图标毛玻璃模糊 (不支持GIF动态图片模糊) + public AlguiViewItem setCatIconBlur(int radius) { + if (icon != null) + icon.setCatBlur(radius); + return this; + } + + + public AlguiViewItem(Context context) { + super(context); + aContext = context; + init(); + ItemList.add(this);//将当前项添加到全局列表 + } + public AlguiViewItem(Context context, CharSequence text) { + this(context); + setCatText(text); + } + + private void init() { + //布局 + setCatSize(AlguiFrameLayout.LayoutParams.MATCH_PARENT, AlguiFrameLayout.LayoutParams.WRAP_CONTENT); + setCatWeight(1); + setCatBackColor(0xFF233E5D); + setOrientation(LinearLayout.HORIZONTAL);//横向 + setGravity(Gravity.CENTER_VERTICAL);//垂直居中 + setCatPadding(5, 3, 5, 3); + + //文本 + text = new AlguiViewText(aContext) + //.setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + //.setCatWeight(1) + .setCatText(TAG) + ; + + setCatTextColor(0xffADB1B7); + setCatTextSize(7); + + //选项布局 + itemLayout = new AlguiLinearLayout(aContext) + .setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + .setCatWeight(1); + itemLayout.setGravity(Gravity.CENTER_VERTICAL | Gravity.END); + + + addView(text); + addView(itemLayout); + initClick();//初始化点击事件 + + + + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewLine.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewLine.java new file mode 100644 index 0000000..71a4f55 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewLine.java @@ -0,0 +1,236 @@ +package com.bytecat.algui.AlguiViews; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.DashPathEffect; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PathEffect; +import android.graphics.Shader; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/11/09 19:50 + * @Describe Algui线条视图 + */ +public class AlguiViewLine extends View { + + public static final String TAG = "AlguiViewLine"; + + //线条样式 + int lineStyle = Style.STYLE_SOLID; // 默认实线 + public static class Style{ + public static final int STYLE_SOLID = 0; //实线 + public static final int STYLE_DASHED = 1; //虚线 + public static final int STYLE_DOTTED = 2; //点线 + public static final int STYLE_WAVE= 3; //波浪线 + } + + Context aContext; + LinearLayout.LayoutParams params;//布局参数 + + Paint mPaint; //画笔 + Path path;//路径 + int colors[]=null;//线条渐变颜色 + float size;//线条大小 + + /** + * 获取布局参数。 + * 通过该方法可以获取控件的布局参数,进而对控件的布局属性进行设置。 + * + * @return 当前的布局参数 (LinearLayout.LayoutParams) + */ + public LinearLayout.LayoutParams getByteParams() { + return params; + } + + + + /** + * 获取画笔对象。 + * 该方法返回一个 Paint 对象,允许你获取和修改绘图样式、颜色等。 + * + * @return 当前的 Paint 对象 + */ + public Paint getBytePaint() { + return mPaint; + } + + + /** + * 获取路径对象。 + * 该方法返回一个 Path 对象,用于绘制复杂的路径或线条。 + * + * @return 当前的 Path 对象 + */ + public Path getBytePath() { + return path; + } + + + + + public AlguiViewLine(Context context) { + super(context); + aContext = context; + init(); + } + + + //设置视图权重 + public AlguiViewLine setCatWeight(float weight) { + params.weight = weight; + requestLayout();//重新计算布局 + return this; + } + + //设置视图外边距 + public AlguiViewLine setCatMargins(float left, float top, float right, float bottom) { + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + + //设置线条样式 + public AlguiViewLine setCatStyle(int style) { + lineStyle = style; + PathEffect effect = null; + switch (lineStyle) { + //实线 + default: + case Style.STYLE_SOLID: + effect = null; + break; + //虚线 + case Style.STYLE_DASHED: + effect = new DashPathEffect(new float[]{10, 5}, 0); + break; + //点线 + case Style.STYLE_DOTTED: + effect = new DashPathEffect(new float[]{2, 10}, 0); + break; + //波浪线 + case Style.STYLE_WAVE: + update(); + return this; + } + mPaint.setPathEffect(effect); + update(); + return this; + } + + //设置线条颜色 + public AlguiViewLine setCatColor(int... color) { + if (color.length == 1) { + //单个颜色 + mPaint.setColor(color[0]); + } else if (color.length > 1) { + //多颜色使用渐变 + colors = color; + invalidate(); + } + + return this; + } + + //设置线条大小 + public AlguiViewLine setCatSize(float width) { + size = (int)dp2px(width); + mPaint.setStrokeWidth(size); + update(); + return this; + } + + //设置父布局 + public AlguiViewLine setCatParentLayout(ViewGroup vg) { + if(vg!=null) + vg.addView(this); + return this; + } + + //更新 + public AlguiViewLine update() { + //宽度拉满,高度为线条大小 + params.width = LinearLayout.LayoutParams.MATCH_PARENT; + params.height = lineStyle == Style.STYLE_WAVE ?(int)size * 10: (int)size - 1; + requestLayout();//重新计算布局 + invalidate();//重新绘制 + return this; + } + + private void init() { + params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT, 1); + setLayoutParams(params); + + setClipToOutline(true);//根据父视图轮廓裁剪 + + path = new Path(); + + mPaint = new Paint(); + mPaint.setAntiAlias(true); //启用抗锯齿 + mPaint.setStyle(Paint.Style.STROKE); //绘制模式 + + setCatSize(1);//默认线大小 + setCatStyle(Style.STYLE_SOLID);//默认实线 + setCatColor(0xFF42424C);//默认颜色 + setCatWeight(1);//权重 + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + int width=getWidth(); + int height=getHeight(); + //存在渐变色时初始化渐变色 + if (colors != null) { + if (mPaint.getShader() == null) { + Shader shader = new LinearGradient(0, 0, width, 0, colors, null, Shader.TileMode.MIRROR); + mPaint.setShader(shader); + } + } + + path.reset();//重置路径 + path.moveTo(0, height / 2); //起点 + if (lineStyle == Style.STYLE_WAVE) { + + //正弦波函数 + for (int i = 0; i < width; i++) { + float y = (float) (height / 2 + Math.sin(i * + 0.1//波浪频率 + ) * + height / 3 //波浪振幅 + ); + path.lineTo(i, y); + } + } else { + path.lineTo(width, height / 2);//结束 + + } + + + //绘制路径 + canvas.drawPath(path, mPaint); + + } + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewSoundWave.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewSoundWave.java new file mode 100644 index 0000000..98c3540 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewSoundWave.java @@ -0,0 +1,482 @@ +package com.bytecat.algui.AlguiViews; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/10/28 09:33 + * @Describe Algui可视化声波监测视图 + */ +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Shader; +import android.graphics.drawable.GradientDrawable; +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.MediaRecorder; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiTools.AlguiToolPermission; +import java.util.Arrays; + +public class AlguiViewSoundWave extends View { + + public static final String TAG = "AlguiViewSoundWave"; + + //声波颜色样式 + int colors[]=null;//渐变颜色 + int colorStyle=StyleColor.STYLE_COLOR_CUSTOMIZE;//默认颜色样式 + public static class StyleColor { + public static final int STYLE_COLOR_CUSTOMIZE=0;//自定义 + public static final int STYLE_COLOR_AMP=1;//每个线条根据振幅小绿中黄大红动态变换 + public static final int STYLE_COLOR_AMP_ALL=2;//所有线条根据振幅小绿中黄大红动态变换 + } + + //声波样式 + int style = Style.STYLE_LINE_DENSE;//默认声波样式 + public static class Style { + public static final int STYLE_LINE_DENSE=0;//密集线 (完整的声纹 拥有丰富的视觉效果) + public static final int STYLE_LINE_INTERVAL=1;//间隔线 (半完整的声纹 会丢失一些声波数据) + public static final int STYLE_LINE_PARTICE=2;//粒子线 (半完整的声纹 会丢失一些声波数据) + public static final int STYLE_LINE_WAVE=3;//波浪线 (半完整的声纹 会丢失一些声波数据) + } + + + Context aContext; + Activity aActivity; + + LinearLayout.LayoutParams params;//布局参数 + GradientDrawable gradientDrawable;//背景 + Paint paint; // 用于绘制波形 + double[] waveform; // 存储音频波形数据的数组 + double loudness;//声音响度 + AudioRecord audioRecord; // 用于录音 + Thread recordingThread; // 录音线程 + int bufferSize; // 缓冲区大小 + boolean isRecording; // 当前是否正在录音 + float sensitivity=5;//声波灵敏度 + + int tBorderSize;//描边大小 + + //Getter Setter + + /** + * 获取布局参数 + * @return LinearLayout.LayoutParams 当前的布局参数 + */ + public LinearLayout.LayoutParams getByteParams() { + return params; + } + + + + /** + * 获取背景绘制对象 + * @return GradientDrawable 当前的背景绘制对象 + */ + public GradientDrawable getByteBack() { + return gradientDrawable; + } + + + /** + * 获取用于绘制波形的画笔 + * @return Paint 当前的绘制画笔 + */ + public Paint getBytePaint() { + return paint; + } + + + + /** + * 获取音频波形数据 + * @return double[] 当前的音频波形数据数组 + */ + public double[] getByteWaveform() { + return waveform; + } + + + + /** + * 获取当前响度值 + * @return double 当前的响度值 + */ + public double getByteLoudness() { + return loudness; + } + + + /** + * 获取 AudioRecord 对象 + * @return AudioRecord 当前的录音对象 + */ + public AudioRecord getByteAudioRecord() { + return audioRecord; + } + + + /** + * 获取录音线程 + * @return Thread 当前的录音线程 + */ + public Thread getByteRecordingThread() { + return recordingThread; + } + + + + /** + * 获取缓冲区大小 + * @return int 当前的缓冲区大小 + */ + public int getByteBufferSize() { + return bufferSize; + } + + + + /** + * 获取当前录音状态 + * @return boolean 当前是否正在录音 + */ + public boolean isRecording() { + return isRecording; + } + + + + /** + * 获取声波灵敏度 + * @return float 当前的声波灵敏度 + */ + public float getByteSensitivity() { + return sensitivity; + } + + + + + + public AlguiViewSoundWave(Context context, Activity activity) { + super(context); + aContext = context; + aActivity = activity; + init(); + } + + private void init() { + params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT, 1); + setLayoutParams(params); + gradientDrawable = new GradientDrawable(); + gradientDrawable.setColor(0xFF20324D); + + setBackground(gradientDrawable); + paint = new Paint(); + paint.setColor(0xC200FF00);//声波颜色 + waveform = new double[0]; //初始波形数组 + isRecording = false; //未录音 + setClipToOutline(true);//根据父视图轮廓裁剪 + setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, 30); + setCatWeight(1); + + } + + + //设置大小 + public AlguiViewSoundWave setCatSize(float w, float h) { + if ((int)w != ViewGroup.LayoutParams.WRAP_CONTENT + && (int) w != ViewGroup.LayoutParams.MATCH_PARENT + && (int)w != ViewGroup.LayoutParams.FILL_PARENT) { + params.width = (int)dp2px(w); + } else { + params.width = (int)w; + } + + if ((int)h != ViewGroup.LayoutParams.WRAP_CONTENT + && (int)h != ViewGroup.LayoutParams.MATCH_PARENT + && (int)h != ViewGroup.LayoutParams.FILL_PARENT) { + params.height = (int)dp2px(h); + } else { + params.height = (int)h; + } + requestLayout();//重新计算布局 + return this; + } + + //设置权重 + public AlguiViewSoundWave setCatWeight(float weight) { + params.weight = weight; + requestLayout();//重新计算布局 + return this; + } + + //设置内边距 + public AlguiViewSoundWave setCatPadding(float left, float top, float right, float bottom) { + setPadding( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + //设置外边距 + public AlguiViewSoundWave setCatMargins(float left, float top, float right, float bottom) { + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + //设置背景颜色 + public AlguiViewSoundWave setCatBackColor(int... backColor) { + if (backColor.length == 1) { + //单个颜色 + gradientDrawable.setColor(backColor[0]); + } else if (backColor.length > 1) { + //多个颜色,使用渐变 + gradientDrawable.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); //渐变方向 + //最后一个元素如果是渐变类型则应用否则默认线性渐变 + if (isGdType(backColor[backColor.length - 1])) { + gradientDrawable.setGradientType(backColor[backColor.length - 1]); + int[] newArray = Arrays.copyOf(backColor, backColor.length - 1);//删除最后一个元素 + gradientDrawable.setColors(newArray);//设置颜色 + } else { + gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT); + gradientDrawable.setColors(backColor);//设置颜色 + } + } + return this; + } + //设置圆角半径 + public AlguiViewSoundWave setCatRadiu(float r) { + gradientDrawable.setCornerRadius(dp2px(r));//圆角 + return this; + } + //设置描边 + public AlguiViewSoundWave setCatBorder(float size, int color) { + int bs = (int)dp2px(size);//新的描边 + gradientDrawable.setStroke(bs, color); + int w=bs - tBorderSize;//计算内边距差值,新描边-旧描边=差值 + this.setPadding(getPaddingLeft() + w, getPaddingTop() + w, getPaddingRight() + w, getPaddingBottom() + w);//设置内边距为描边宽度防止描边覆盖子视图 + tBorderSize = bs; + return this; + + } + + //设置声波灵敏度 + public AlguiViewSoundWave setCatSensitivity(float s) { + sensitivity = s; + invalidate(); + return this; + } + //设置声波样式 + public AlguiViewSoundWave setCatStyle(int type) { + style = type; + invalidate(); + return this; + } + //设置声波颜色样式 + public AlguiViewSoundWave setCatColorStyle(int type) { + colorStyle = type; + invalidate(); + return this; + } + + //设置声波颜色 + public AlguiViewSoundWave setCatColor(int... color) { + //只有颜色样式为自定义时才设置 + if (colorStyle == StyleColor.STYLE_COLOR_CUSTOMIZE) { + if (color.length == 1) { + //单个颜色 + paint.setColor(color[0]); + } else if (color.length > 1) { + //多个颜色,使用渐变 + colors = color; + invalidate(); + } + + } + return this; + } + + //设置声波发光效果 (这可能会掉帧) + public AlguiViewSoundWave setCatGlow(float radius, int color) { + paint.setShadowLayer(radius, 0, 0, color); + return this; + } + //设置父布局 + public AlguiViewSoundWave setCatParentLayout(ViewGroup vg) { + if (vg != null) + vg.addView(this); + return this; + } + + //开始录音 + public AlguiViewSoundWave startRecording() { + if (!isRecording) { + //申请录音权限 + AlguiToolPermission.getPermission(aActivity, Manifest.permission.RECORD_AUDIO, new AlguiToolPermission.PermissionCallback() { + @Override + public void run(boolean consequence) { + if (consequence) { + AlguiLog.d(TAG,"授予了录音权限"); + int source = MediaRecorder.AudioSource.MIC; //录音源 + int samplingRate = 44100; //采样率 + int channel = AudioFormat.CHANNEL_IN_MONO; //通道 + int format = AudioFormat.ENCODING_PCM_16BIT; //编码格式 + + bufferSize = AudioRecord.getMinBufferSize(samplingRate, channel, format); + + audioRecord = new AudioRecord(source, samplingRate, channel, format, bufferSize); + audioRecord.startRecording(); //开始录音 + isRecording = true; //正在录音 + recordingThread = new Thread(new Runnable() { + @Override + public void run() { + short[] buffer = new short[bufferSize]; //短整型缓冲区 + while (isRecording) { + int readSize = audioRecord.read(buffer, 0, buffer.length); + if (readSize > 0) { + double[] normalizedData = new double[readSize]; //归一化数据数组 + + double sum = 0.0; + for (int i = 0; i < readSize; i++) { + normalizedData[i] = buffer[i] / 32768.0; //归一化 + sum += normalizedData[i] * normalizedData[i]; //计算平方和 + } + + //计算均方根(RMS) + double rms = Math.sqrt(sum / readSize); + + waveform = normalizedData; //更新波形数据 + loudness = rms; //更新响度 + postInvalidate(); //重绘 + } + } + } + }); + + recordingThread.start(); + } else { + AlguiLog.d(TAG,"未授予录音权限"); + } + } + }); + + } + return this; + } + + //停止录音 + public AlguiViewSoundWave stopRecording() { + if (isRecording) { + isRecording = false; + audioRecord.stop(); + audioRecord.release(); + audioRecord = null; + recordingThread = null; + invalidate(); // 请求重绘 + } + return this; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + float width = getWidth(); + float height = getHeight(); + float halfHeight=height / 2;//高度中间 + if (colors != null) { + if (paint.getShader() == null) { + Shader shader = new LinearGradient(0, 0, 0, height, colors, null, Shader.TileMode.CLAMP); + paint.setShader(shader); + } + } + if (!isRecording) { + canvas.drawLine(0, halfHeight, width, halfHeight, paint);//起始xy 结束xy + } + //绘制声音波纹 + if (waveform.length > 0) { + //调试rms + //paint.setColor(Color.WHITE); + //canvas.drawText("rms "+loudness, 2, 15, paint); + + if (colorStyle == StyleColor.STYLE_COLOR_AMP_ALL) { + if (loudness < 0.02) { + paint.setColor(Color.GREEN); //小 + } else if (loudness < 0.04) { + paint.setColor(Color.YELLOW); //中 + } else { + paint.setColor(Color.RED); //大 + } + } + + + for (int i = 0; i < waveform.length; i++) { + float x = ((float) i / waveform.length * width);//根据每个波点索引依次增加x 最后+乘数代表每条线x间隔 + float y = halfHeight - (float) (waveform[i] * halfHeight) * sensitivity;//高度从中间开始减去波纹大小为结束点 + + if (colorStyle == StyleColor.STYLE_COLOR_AMP) { + if (y > halfHeight / 2) { + paint.setColor(Color.GREEN); //小 + } else if (y > halfHeight / 3) { + paint.setColor(Color.YELLOW); //中 + } else { + paint.setColor(Color.RED); //大 + } + } + switch (style) { + case Style.STYLE_LINE_DENSE://密集 + canvas.drawLine(x, height / 2, x, y, paint);//起始xy 结束xy + break; + case Style.STYLE_LINE_INTERVAL://间隔 + x *= 50; + canvas.drawLine(x, height / 2, x, y, paint);//起始xy 结束xy + break; + case Style.STYLE_LINE_PARTICE://粒子 + x *= 50; + canvas.drawCircle(x, y, 1, paint); //圆 + break; + case Style.STYLE_LINE_WAVE://波浪 + x *= 50; + canvas.drawCircle(x, y, 5, paint); //圆 + break; + default://默认密集 + canvas.drawLine(x, height / 2, x, y, paint);//起始xy 结束xy + break; + + } + } + } + } + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + //判断是否为渐变类型 + public boolean isGdType(int typeIndex) { + return typeIndex == GradientDrawable.LINE || + typeIndex == GradientDrawable.LINEAR_GRADIENT || + typeIndex == GradientDrawable.OVAL || + typeIndex == GradientDrawable.RADIAL_GRADIENT || + typeIndex == GradientDrawable.RECTANGLE || + typeIndex == GradientDrawable.RING || + typeIndex == GradientDrawable.SWEEP_GRADIENT; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewText.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewText.java new file mode 100644 index 0000000..89a3154 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewText.java @@ -0,0 +1,528 @@ +package com.bytecat.algui.AlguiViews; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Shader; +import android.graphics.Typeface; +import android.graphics.drawable.GradientDrawable; +import android.text.Html; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.util.Linkify; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiManager.AlguiObjectManager; +import com.bytecat.algui.AlguiTools.AlguiLinkMovementMethod; +import java.util.Arrays; +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/10/26 11:00 + * @Describe Algui文本视图 + */ +public class AlguiViewText extends TextView { + + public static final String TAG = "AlguiViewText"; + + Context aContext; + LinearLayout.LayoutParams params;//文本布局参数 + GradientDrawable gradientDrawable;//文本背景 + int tBorderSize;//描边大小 + + boolean isLink;//是否自动识别并处理超链接 + //滚动文本效果相关 + boolean roll_isRoll=false;//开关 + public float roll_mOffsetX = 0;//偏移量 + public int roll_mTextWidth;//文本宽度 + public float roll_mSpeed = 2;//速度 + + //渐变文本效果相关 + boolean grad_isGrad=false;//开关 + public Matrix grad_mMatrix;//矩阵 + public float grad_mTranslate;//平移量 + public float grad_colorSpeed = 1f;//速度 + public LinearGradient grad_mLinearGradient;//线性渐变 + public int[] grad_colors = null;//渐变颜色 + + + //点击事件回调反馈 + AlguiCallback.Click call; + boolean isInitClick=false;//是否已经初始化点击事件 + boolean isChecked=false; + //初始化内部点击事件 + private void initClick() { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + callClick(!isChecked); + } + }); + isInitClick = true; + } + //设置点击事件回调反馈接口 + public AlguiViewText setCatCallback(AlguiCallback.Click c) { + if (c == null) { + setOnClickListener(null); + isInitClick = false; + } else { + call = c; + if (!isInitClick) { + initClick(); + } + } + return this; + } + + + //获取点击事件回调反馈接口 + public AlguiCallback.Click getByteCallback() { + return call; + } + //代码执行点击事件 + public AlguiViewText callClick(boolean b) { + isChecked = b; + if (call != null) + call.click(isChecked); + return this; + } + + + /** + * 获取文本布局参数 + * + * @return 当前的文本布局参数 + */ + public LinearLayout.LayoutParams getByteParams() { + return params; + } + + + /** + * 获取文本背景 + * + * @return 当前的文本背景 + */ + public GradientDrawable getByteBack() { + return gradientDrawable; + } + + CharSequence sText;//文本 + int[] sBackColors,sTextColors;//背景和文本颜色 + float sStrokeSize=-1;//描边大小 + int sStrokeColor=-1;//描边颜色 + float sFilletRadiu=-1;//圆角半径 + float sTextSize=-1;//文本大小 + float sGlowRadius=-1;//发光半径 + int sGlowColor=-1;//发光颜色 + + //获取样式 + public CharSequence getByteStyleText() { return sText; } + public int[] getByteStyleBackColors() { return sBackColors; } + public int[] getByteStyleTextColos() { return sTextColors; } + public float getByteStyleBorderSize() { return sStrokeSize; } + public int getByteStyleBorderColor() { return sStrokeColor; } + public float getByteStyleRadius() { return sFilletRadiu; } + public float getByteStyleTextSize() { return sTextSize; } + public float getByteStyleGlowRadius() { return sGlowRadius; } + public int getByteStyleGlowColor() { return sGlowColor; } + + boolean isTemStyle=false; + //设置是否临时改变样式而不保存到变量 + public AlguiViewText setTemStyle(boolean isTem) { + isTemStyle = isTem; + return this; + } + + + //设置发光效果 + public AlguiViewText setCatTextGlow(float radius, int color) { + if (!isTemStyle) { + sGlowRadius = radius; + sGlowColor = color; + } + + setShadowLayer(radius, 0, 0, color); + updateCatTextWidth(); + return this; + } + //设置动态渐变效果启动状态 + public AlguiViewText setCatTextMoveGrad(boolean b) { + grad_isGrad = b; + //没有渐变颜色使用默认的 + if (b) { + if (grad_colors == null) { + grad_colors = new int[]{ 0xFFff00cc, 0xFFffcc00, 0xFF00ffcc, 0xFFff0066}; + } + } else { + grad_colors = null; + } + + invalidate(); + return this; + } + //设置渐变速度 + public AlguiViewText setCatTextGradSpeed(float s) { + grad_colorSpeed = s; + invalidate(); + return this; + } + //设置滚动效果启动状态 + public AlguiViewText setCatTextRoll(boolean b) { + if (b == roll_isRoll) { + return this; + } + roll_isRoll = b; + if(b){ + setMaxLines(1);//最大显示一行 + }else{ + setMaxLines(0);//最大显示一行 + } + //有抢夺 + /* if (roll_isRoll) { + setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + setCatWeight(1); + //setMaxLines(1);//最大显示一行 + }*/ + invalidate(); + return this; + } + //设置滚动速度 + public AlguiViewText setCatTextRollSpeed(float s) { + roll_mSpeed = s; + invalidate(); + return this; + } + //更新文本宽度 + public AlguiViewText updateCatTextWidth() { + roll_mTextWidth = (int)getPaint().measureText(getText().toString()); + invalidate(); + return this; + } + //设置文本 + public AlguiViewText setCatText(CharSequence text, Object... args) { + if (!isTemStyle) + sText = text; + if (text != null) { + String str = text.toString(); + //检查HTML文本 + if (str.indexOf("<") != -1 && str.indexOf(">") != -1) { + setCatTextHtml(str);//设置html文本 + } else if (args != null && args.length > 0) { + //对于需要格式化文本 + String s = String.format(str, args); + setText(s); + setCatTextIsLink(isLink); + } else { + //普通 + setText(text); + setCatTextIsLink(isLink); + } + + } else { + setText(""); + } + + updateCatTextWidth();//更新文本宽度 + return this; + } + //设置Html文本 + public AlguiViewText setCatTextHtml(String text, Object... args) { + if (!isTemStyle) + sText = text; + if (text != null) { + if (args != null && args.length > 0) { + text = String.format(text, args); + } + setText(Html.fromHtml(text)); + } else + setText(""); + + setCatTextIsLink(isLink); + updateCatTextWidth();//更新文本宽度 + return this; + } + + + + //设置文本颜色 + public AlguiViewText setCatTextColor(int... color) { + if (!isTemStyle) + sTextColors = color; + if (color.length == 1) { + //单个颜色关闭渐变效果 + setTextColor(color[0]); + setCatTextMoveGrad(false); + } else if (color.length > 1) { + //多个颜色则启用渐变效果 + grad_colors = color; + invalidate(); + } + return this; + } + //设置文本大小 + public AlguiViewText setCatTextSize(float size) { + if (!isTemStyle) + sTextSize = size; + setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(size)); + updateCatTextWidth();//更新文本宽度 + return this; + } + //设置Assets文件夹字体文件作为文本字体 + public AlguiViewText setCatTextTFAssets(String assetsTfFileName) { + setCatTextTFAssets(assetsTfFileName, Typeface.NORMAL); + return this; + }//重载+样式 + public AlguiViewText setCatTextTFAssets(String assetsTfFileName, int style) { + setTypeface( + assetsTfFileName != null ? + Typeface.createFromAsset(aContext.getAssets(), assetsTfFileName) + : null, style); + updateCatTextWidth();//更新文本宽度 + return this; + } + + //设置布局大小 + public AlguiViewText setCatSize(float w, float h) { + if ((int)w != ViewGroup.LayoutParams.WRAP_CONTENT + && (int) w != ViewGroup.LayoutParams.MATCH_PARENT + && (int)w != ViewGroup.LayoutParams.FILL_PARENT) { + params.width = (int)dp2px(w); + } else { + params.width = (int)w; + } + + if ((int)h != ViewGroup.LayoutParams.WRAP_CONTENT + && (int)h != ViewGroup.LayoutParams.MATCH_PARENT + && (int)h != ViewGroup.LayoutParams.FILL_PARENT) { + params.height = (int)dp2px(h); + } else { + params.height = (int)h; + } + requestLayout();//重新计算布局 + return this; + } + //设置权重 + public AlguiViewText setCatWeight(float weight) { + params.weight = weight; + requestLayout();//重新计算布局 + return this; + } + + //设置内边距 + public AlguiViewText setCatPadding(float left, float top, float right, float bottom) { + setPadding( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + + //设置外边距 + public AlguiViewText setCatMargins(float left, float top, float right, float bottom) { + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + //设置重力 + public AlguiViewText setCatTextGravity(int g) { + //有抢夺 + /*if (g == Gravity.CENTER_HORIZONTAL ||//水平居中 + g == Gravity.RIGHT ||//右对齐 + g == Gravity.CENTER ||//水平和垂直都居中 + g == Gravity.END//内容结束 + ) { + setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + setCatWeight(1); + }*/ + setGravity(g); + return this; + } + //设置是否自动识别转换文本中的超链接到可点击跳转 + public AlguiViewText setCatTextIsLink(boolean b) { + isLink=b; + if (b) { + Linkify.addLinks(this, Linkify.WEB_URLS);//自动识别链接 + setMovementMethod(AlguiLinkMovementMethod.getInstance()); + } else { + setMovementMethod(null); + } + return this; + } + //设置背景颜色 + public AlguiViewText setCatBackColor(int... backColor) { + if (!isTemStyle) + sBackColors = backColor; + if (backColor.length == 1) { + //单个颜色 + gradientDrawable.setColor(backColor[0]); + } else if (backColor.length > 1) { + //多个颜色,使用渐变 + gradientDrawable.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT); //渐变方向 + //最后一个元素如果是渐变类型则应用否则默认线性渐变 + if (isGdType(backColor[backColor.length - 1])) { + gradientDrawable.setGradientType(backColor[backColor.length - 1]); + int[] newArray = Arrays.copyOf(backColor, backColor.length - 1);//删除最后一个元素 + gradientDrawable.setColors(newArray);//设置颜色 + } else { + gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT); + gradientDrawable.setColors(backColor);//设置颜色 + } + } + return this; + } + //设置圆角半径 + public AlguiViewText setCatRadiu(float r) { + if (!isTemStyle) + sFilletRadiu = r; + gradientDrawable.setCornerRadius(dp2px(r));//圆角 + return this; + } + //设置描边 + public AlguiViewText setCatBorder(float size, int color) { + if (!isTemStyle) + sStrokeSize = size; + sStrokeColor = color; + int bs = (int)dp2px(size);//新的描边 + gradientDrawable.setStroke(bs, color); + int w=bs - tBorderSize;//计算内边距差值,新描边-旧描边=差值 + this.setPadding(getPaddingLeft() + w, getPaddingTop() + w, getPaddingRight() + w, getPaddingBottom() + w);//设置内边距为描边宽度防止描边覆盖子视图 + tBorderSize = bs; + return this; + } + + + //设置父布局 + public AlguiViewText setCatParentLayout(ViewGroup vg) { + if (vg != null) + vg.addView(this); + return this; + } + + + + + public AlguiViewText(Context c) { + super(c); + aContext = c; + init(); + } + + public AlguiViewText(Context c, CharSequence text) { + this(c); + setCatText(text); + } + private void init() { + gradientDrawable = new GradientDrawable(); + setBackground(gradientDrawable); + + params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + setLayoutParams(params); + setClipToOutline(true);//根据父视图轮廓裁剪 + updateCatTextWidth();//更新文本宽度 + setCatText(TAG); + setCatTextSize(7); + setCatTextColor(0xFFADB1B7); + setTag(TAG);//设置标识符 + AlguiObjectManager.addView(this); + } + + @Override + protected void onDraw(Canvas canvas) { + //滚动文本 + if (roll_isRoll) { + //判断当前偏移量是否小于文本宽度的负值 + if (roll_mOffsetX < -roll_mTextWidth) { + //如果文本完全滚出视图,重置偏移量为视图宽度 + roll_mOffsetX = getWidth(); + } + //减少偏移量,实现滚动效果 + roll_mOffsetX -= roll_mSpeed; + + TextPaint textPaint = getPaint(); + textPaint.setColor(getCurrentTextColor()); + + StaticLayout staticLayout = new StaticLayout(getText(), textPaint, roll_mTextWidth, + Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); + canvas.save(); + canvas.translate(roll_mOffsetX, 0);//绘制坐标 + staticLayout.draw(canvas); //绘制文本 + canvas.restore(); + + } + + //需要渐变时 + if (grad_colors != null) { + //初始化线性渐变 + if (grad_mLinearGradient == null) { + //线性渐变 左到右 + grad_mLinearGradient = new LinearGradient( + 0, getHeight() / 2, //渐变起始坐标 + getWidth(), 0,//渐变结束坐标 + grad_colors, //渐变颜色 + null, //渐变比例 null=均匀分布 + Shader.TileMode.MIRROR//超出渐变范围之外的处理方式,MIRROR镜像重复显示 + ); + getPaint().setShader(grad_mLinearGradient);//设置文本的画笔为这个线性渐变效果 + } + + } + + //如果启用了文本动态渐变 + if (grad_isGrad) { + //初始化矩阵 + if (grad_mMatrix == null) { + grad_mMatrix = new Matrix(); + } + //更新平移量 控制渐变移动 + grad_mTranslate += grad_colorSpeed;//平移 + grad_mMatrix.setTranslate(grad_mTranslate, 0);//设置矩阵的平移距离xy + grad_mLinearGradient.setLocalMatrix(grad_mMatrix);//线性渐变更新局部矩阵 + } + + //如果滚动效果开启时将不使用父类的绘制 + if (!roll_isRoll) { + super.onDraw(canvas); + } + + if (roll_isRoll || grad_isGrad) { + //对于动态效果则重新绘制,进行递归 + postInvalidateOnAnimation(); + + } + + + } + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + //判断是否为渐变类型 + public boolean isGdType(int typeIndex) { + return typeIndex == GradientDrawable.LINE || + typeIndex == GradientDrawable.LINEAR_GRADIENT || + typeIndex == GradientDrawable.OVAL || + typeIndex == GradientDrawable.RADIAL_GRADIENT || + typeIndex == GradientDrawable.RECTANGLE || + typeIndex == GradientDrawable.RING || + typeIndex == GradientDrawable.SWEEP_GRADIENT; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewTriangle.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewTriangle.java new file mode 100644 index 0000000..6ce137f --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewTriangle.java @@ -0,0 +1,223 @@ +package com.bytecat.algui.AlguiViews; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/23 09:21 + * @Describe Algui三角形视图 + */ +public class AlguiViewTriangle extends View { + + public static final String TAG = "AlguiViewTriangle"; + private Context aContext; + private Paint trianglePaint; // 画笔 + private Path trianglePath; // 路径 + private LinearLayout.LayoutParams params;//布局参数 + + //三角形绘制类型 + public static class Type{ + public static final int RIGHT_ANGLE_LEFT_BOTTOM = 0; // 直角三角形_位置左下角 + public static final int RIGHT_ANGLE_LEFT_TOP = 1; // 直角三角形_位置左上角 + public static final int RIGHT_ANGLE_RIGHT_BOTTOM = 2; // 直角三角形_位置右下角 + public static final int RIGHT_ANGLE_RIGHT_TOP = 3; // 直角三角形_位置右上角 + + public static final int EQUILATERAL_RIGHT = 4; // 等边三角形_位置右边 + public static final int EQUILATERAL_LEFT = 5; // 等边三角形_位置左边 + public static final int EQUILATERAL_TOP = 6; // 等边三角形_位置上边 + public static final int EQUILATERAL_BOTTOM = 7; // 等边三角形_位置下边 + } + + private int drawType =Type.EQUILATERAL_BOTTOM; //绘制类型 + + public int size; + + /** + * 获取画笔 + * + * @return 当前的画笔对象 + */ + public Paint getBytePaint() { + return trianglePaint; + } + + + /** + * 获取路径 + * + * @return 当前的路径对象 + */ + public Path getBytePath() { + return trianglePath; + } + + + /** + * 获取布局参数 + * + * @return 当前的布局参数对象 + */ + public LinearLayout.LayoutParams getByteParams() { + return params; + } + + + + // 设置大小 + public AlguiViewTriangle setCatSize(float size) { + this.size = (int)dp2px(size); + params.width = this.size ; + params.height = this.size; + requestLayout();//重新计算布局 + invalidate();//重绘 + return this; + } + + //设置外边距 + public AlguiViewTriangle setCatMargins(float left, float top, float right, float bottom) { + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + // 设置颜色 + public AlguiViewTriangle setCatColor(int color) { + trianglePaint.setColor(color); // 设置颜色 + return this; + } + + //设置三角形类型 + public AlguiViewTriangle setCatType(int type) { + drawType = type; + invalidate();//重绘 + return this; + } + + //设置父布局 + public AlguiViewTriangle setCatParentLayout(ViewGroup vg) { + if(vg!=null) + vg.addView(this); + return this; + } + + + public AlguiViewTriangle(Context context) { + super(context); + aContext = context; + init(); + } + + + private void init() { + trianglePaint = new Paint(); // 初始化画笔 + trianglePaint.setStyle(Paint.Style.FILL); // 设置样式为填充 + trianglePaint.setColor(0xff1E3045); // 设置颜色 + trianglePaint.setAntiAlias(true); // 启用抗锯齿 + + setBackgroundColor(Color.TRANSPARENT);//背景透明 + + + params = new LinearLayout.LayoutParams(0, 0); + setLayoutParams(params); + setClipToOutline(true);//根据父视图轮廓裁剪 + setCatSize(15); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + //根据三角形类型处理绘制路径 + switch (drawType) { + case Type.RIGHT_ANGLE_LEFT_BOTTOM: + // 处理直角三角形_位置左下角 + trianglePath = new Path(); // 初始化路径 + trianglePath.moveTo(0, 0); // 从视图左上角开始 + trianglePath.lineTo(0, getHeight()); // 移动到视图左下角 + trianglePath.lineTo(getWidth(), getHeight()); // 移动到视图右下角 + break; + case Type.RIGHT_ANGLE_LEFT_TOP: + // 处理直角三角形_位置左上角 + trianglePath = new Path(); // 初始化路径 + trianglePath.moveTo(0, getHeight()); // 从视图左下角开始 + trianglePath.lineTo(0, 0); // 移动到视图左上角 + trianglePath.lineTo(getWidth(), 0); // 移动到视图右上角 + break; + case Type.RIGHT_ANGLE_RIGHT_BOTTOM: + // 处理直角三角形_位置右下角 + trianglePath = new Path(); // 初始化路径 + trianglePath.moveTo(0, getHeight()); // 从视图左下角开始 + trianglePath.lineTo(getWidth(), getHeight()); // 移动到视图右下角 + trianglePath.lineTo(getWidth(), 0); // 移动到视图右上角 + break; + case Type.RIGHT_ANGLE_RIGHT_TOP: + // 处理直角三角形_位置右上角 + trianglePath = new Path(); // 初始化路径 + trianglePath.moveTo(0, 0); // 从视图左上角开始 + trianglePath.lineTo(getWidth(), 0); // 移动到视图右上角 + trianglePath.lineTo(getWidth(), getHeight()); // 移动到视图右下角 + break; + case Type.EQUILATERAL_RIGHT: + // 处理等边三角形_位置右边 + trianglePath = new Path(); // 初始化路径 + trianglePath.moveTo(0, getHeight() / 2); // 从视图左边中心开始 + trianglePath.lineTo(getWidth(), getHeight()); // 移动到视图右下角 + trianglePath.lineTo(getWidth(), 0); // 移动到视图右上角 + break; + case Type.EQUILATERAL_LEFT: + // 处理等边三角形_位置左边 + trianglePath = new Path(); // 初始化路径 + trianglePath.moveTo(getWidth(), getHeight() / 2); // 从视图右边中心开始 + trianglePath.lineTo(0, getHeight()); // 移动到视图左下角 + trianglePath.lineTo(0, 0); // 移动到视图左上角 + break; + case Type.EQUILATERAL_TOP: + // 处理等边三角形_位置上边 + trianglePath = new Path(); // 初始化路径 + trianglePath.moveTo(getWidth() / 2, getHeight()); // 从视图下边中心开始 + trianglePath.lineTo(0, 0); // 移动到视图左上角 + trianglePath.lineTo(getWidth(), 0); // 移动到视图右上角 + break; + case Type.EQUILATERAL_BOTTOM: + // 处理等边三角形_位置下边 + trianglePath = new Path(); // 初始化路径 + trianglePath.moveTo(getWidth() / 2, 0); // 从视图上边中心开始 + trianglePath.lineTo(0, getHeight()); // 移动到视图左下角 + trianglePath.lineTo(getWidth(), getHeight()); // 移动到视图右下角 + break; + default: + // 未知直接结束 + return; + } + trianglePath.close(); // 闭合此路径 + + // 裁剪画布此路径内部的区域作为绘制区域 + canvas.clipPath(trianglePath); + // 绘制此路径内部的区域 + canvas.drawPath(trianglePath, trianglePaint); + } + + + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewWeb.java b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewWeb.java new file mode 100644 index 0000000..0c3cc46 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiViews/AlguiViewWeb.java @@ -0,0 +1,338 @@ +package com.bytecat.algui.AlguiViews; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/11/12 16:29 + * @Describe Algui网络视图 + */ +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.drawable.GradientDrawable; +import android.net.Uri; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.LinearLayout; + +public class AlguiViewWeb extends WebView { + + public static final String TAG = "AlguiViewWeb"; + + Context aContext; + Activity aActivity; + LinearLayout.LayoutParams params;//布局参数 + GradientDrawable gradientDrawable;//背景 + + int tBorderSize;//描边大小 + + /** + * 获取布局参数 + * + * @return 当前的布局参数 + */ + public LinearLayout.LayoutParams getByteParams() { + return params; + } + + + + /** + * 获取背景 + * + * @return 当前的背景 + */ + public GradientDrawable getByteBack() { + return gradientDrawable; + } + + + + //设置布局大小 + public AlguiViewWeb setCatSize(float w, float h) { + if ((int)w != ViewGroup.LayoutParams.WRAP_CONTENT + && (int) w != ViewGroup.LayoutParams.MATCH_PARENT + && (int)w != ViewGroup.LayoutParams.FILL_PARENT) { + params.width = (int)dp2px(w); + } else { + params.width = (int)w; + } + + if ((int)h != ViewGroup.LayoutParams.WRAP_CONTENT + && (int)h != ViewGroup.LayoutParams.MATCH_PARENT + && (int)h != ViewGroup.LayoutParams.FILL_PARENT) { + params.height = (int)dp2px(h); + } else { + params.height = (int)h; + } + requestLayout();//重新计算布局 + return this; + } + //设置权重 + public AlguiViewWeb setCatWeight(float weight) { + params.weight = weight; + requestLayout();//重新计算布局 + return this; + } + + //设置外边距 + public AlguiViewWeb setCatMargins(float left, float top, float right, float bottom) { + params.setMargins( + (int)dp2px(left), + (int)dp2px(top), + (int)dp2px(right), + (int)dp2px(bottom)); + return this; + } + + //设置背景颜色 + public AlguiViewWeb setCatBackColor(int backColor) { + setBackgroundColor(backColor); + return this; + } + //设置圆角半径 + public AlguiViewWeb setCatRadiu(float r) { + gradientDrawable.setCornerRadius(dp2px(r));//圆角 + return this; + } + + //设置缩放 + public AlguiViewWeb setCatZoom(int scaleInPercent) { + setInitialScale(scaleInPercent); + return this; + } + + //通用简单加载WEB视图 + //支持:加载网站,加载HTML代码,加载HTML文件 + public AlguiViewWeb setCatWeb(String website_htmlcode_htmlfile) { + if (website_htmlcode_htmlfile != null) { + //字符串开头是http或https则加载网站 + if (website_htmlcode_htmlfile.startsWith("http://") || website_htmlcode_htmlfile.startsWith("https://")) { + setCatWebsite(website_htmlcode_htmlfile); + //对于html代码检查必有点标签特征 + } else if (website_htmlcode_htmlfile.contains("<") && website_htmlcode_htmlfile.contains(">")) { + setCatHtml(website_htmlcode_htmlfile); + //其它情况默认识别为本地代码文件 + } else { + setCatHtmlFile(website_htmlcode_htmlfile); + } + } + return this; + } + //加载网站 网站链接 + public AlguiViewWeb setCatWebsite(String url) { + loadUrl(url); + return this; + } + //加载网站 网站链接,缩放百分比 + public AlguiViewWeb setCatWebsite(String url, int scaleInPercent) { + loadUrl(url); + setInitialScale(scaleInPercent); + return this; + } + + //加载本地html代码文件 + public AlguiViewWeb setCatHtmlFile(String filePath) { + if (filePath == null) { + loadUrl(filePath); + return this; + } + //如果路径开头是assets文件夹 不区分大小写 + if (filePath.toLowerCase().startsWith("/assets/") || filePath.toLowerCase().startsWith("assets/")) { + //修复assets字符串 + int lastSlashIndex = filePath.lastIndexOf('/'); + + if (lastSlashIndex != -1) { + filePath="file:///android_asset/"+filePath.substring(lastSlashIndex + 1); + }else{ + filePath="file:///android_asset/"+filePath; + } + + }else if(!filePath.contains("/")){ + //对于纯文件名 识别为assets文件夹下的文件 + filePath="file:///android_asset/"+filePath; + }else{ + loadUrl(filePath); + } + + + return this; + } + + //加载html代码 资源根目录路径(本地&服务器),网络代码,MIME类型,编码格式,上一个网络代码(历史记录) + public AlguiViewWeb setCatHtml(@Nullable String baseUrl, @NonNull String data, @Nullable String mimeType, @Nullable String encoding, @Nullable String historyUrl) { + loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl); + return this; + } + //加载html代码 资源根目录路径(本地&服务器),网络代码,MIME类型,编码格式 + public AlguiViewWeb setCatHtml(@Nullable String baseUrl, @NonNull String data, @Nullable String mimeType, @Nullable String encoding) { + loadDataWithBaseURL(baseUrl, data, mimeType, encoding, null); + return this; + } + //加载html代码 资源根目录路径(本地&服务器),网络代码,MIME类型 + public AlguiViewWeb setCatHtml(@Nullable String baseUrl, @NonNull String data, @Nullable String mimeType) { + loadDataWithBaseURL(baseUrl, data, mimeType, "UTF-8", null); + return this; + } + //加载html代码 资源根目录路径(本地&服务器),网络代码 + public AlguiViewWeb setCatHtml(@Nullable String baseUrl, @NonNull String data) { + loadDataWithBaseURL(baseUrl, data, "text/html", "UTF-8", null); + return this; + } + //加载html代码 网络代码 + public AlguiViewWeb setCatHtml(@NonNull String data) { + loadDataWithBaseURL(null, data, "text/html", "UTF-8", null); + return this; + } + + //设置父布局 + public AlguiViewWeb setCatParentLayout(ViewGroup vg) { + if (vg != null) + vg.addView(this); + return this; + } + public AlguiViewWeb(Context context, Activity activity) { + super(context); + aContext = context; + aActivity = activity; + init(); + } + public AlguiViewWeb(Context context, Activity activity, String website_htmlcode_htmlfile) { + this(context, activity); + setCatWeb(website_htmlcode_htmlfile); + } + + private void init() { + params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1); + gradientDrawable = new GradientDrawable(); + + setLayoutParams(params); + setBackground(gradientDrawable); //设置背景 + setLayerType(View.LAYER_TYPE_HARDWARE, null);//硬件加速 + + //Web属性 + setClipChildren(true);//子视图超过边界时自动裁剪 + setClipToOutline(true);//根据父视图轮廓裁剪 + getSettings().setJavaScriptEnabled(true);// 允许在 WebView 中执行 JavaScript 代码, + getSettings().setLoadsImagesAutomatically(true);//自动加载图片。 + getSettings().setBlockNetworkImage(false);//是否阻塞网络图片加载。 + getSettings().setDomStorageEnabled(true);//启用或禁用 DOM Storage API。 + getSettings().setAllowFileAccess(true);//是否允许 WebView 访问文件。 + getSettings().setGeolocationEnabled(true);//启用或禁用地理位置定位。 + getSettings().setDatabaseEnabled(true);//启用或禁用数据库。 + getSettings().setJavaScriptCanOpenWindowsAutomatically(true);//设置 JavaScript 是否可以自动打开窗口。 + getSettings().setDefaultTextEncodingName("utf-8");//设置默认的文本编码 + + //Web自适应 + getSettings().setUseWideViewPort(true);//页面自适应屏幕宽度 + getSettings().setLoadWithOverviewMode(true);//图片自适应屏幕大小 + getSettings().setSupportZoom(true); //是否支持缩放 + getSettings().setBuiltInZoomControls(true); //是否显示缩放控制按钮 + getSettings().setDisplayZoomControls(false); //是否隐藏默认的缩放控件 + //getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);//单列布局 + //setInitialScale(50); //设置缩放比例,避免页面加载过大 + + setWebViewClient(new WebViewClient() { + @Override + public void onPageStarted(WebView view, String url, android.graphics.Bitmap favicon) { + //页面加载开始 + //super.onPageStarted(view, url, favicon);//显示加载动画 + } + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + //页面加载出错 + //跳转到系统默认的浏览器 + //AlguiLog.d(TAG + " 页面加载失败:跳转默认游览器"); + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(failingUrl)); + if (!(aActivity instanceof Context)) + aActivity.startActivity(intent); + } + @Override + public void onPageFinished(WebView view, String url) { + //页面加载完成 + //super.onPageFinished(view, url);//隐藏加载动画 + } + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + //使其网站中的所有超链接直接跳转而不是打开游览器跳转 + super.shouldOverrideUrlLoading(view, url); + view.loadUrl(url); + return true; + } + + }); + + setCatBackColor(0xff20324D);//背景颜色 + + //loadWebsite("https://www.w3school.com.cn/index.html");//加载网站 + //loadCodeFile("/assets/AlguiWebExample.html");//加载代码文件 + + //初始演示HTML内容 + setCatHtml + ( + //资源根目录 (也可以是服务器根目录) + //HTML可直接引用该根目录中的资源,这里默认Assets文件夹 + "file:///android_asset/", + //当前HTML页面 其中引用的资源都是上方根目录中的 + //---------------- + "" + + //CSS + "" + + //js + "" + + //HTML + "

这是AlguiWeb示例页面 HTML,CSS,JS学习

" + + "

This is the AlguiWeb page

" + + "
" + + "" + + "", + //---------------- + "text/html",//MIME类型 + "UTF-8", //编码格式 + null//上一个页面 (历史记录可以在当前跳转到之前 不需要就传null) + ); + + + + } + + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWin2FA.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWin2FA.java new file mode 100644 index 0000000..77942ab --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWin2FA.java @@ -0,0 +1,1267 @@ +package com.bytecat.algui.AlguiWindows; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/29 17:47 + * @Describe 网络验证窗口 + */ +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.drawable.AnimatedImageDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.icu.text.SimpleDateFormat; +import android.icu.util.GregorianCalendar; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.view.Gravity; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.Toast; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import com.bytecat.algui.AlguiTools.AlguiToolCache; +import com.bytecat.algui.AlguiTools.AlguiToolImage; +import com.bytecat.algui.AlguiTools.AlguiToolNetwork; +import com.bytecat.algui.AlguiTools.AlguiToolPermission; +import com.bytecat.algui.AlguiTools.AlguiToolRC4; +import com.bytecat.algui.AlguiViews.AlguiLinearLayout; +import com.bytecat.algui.AlguiViews.AlguiViewButton; +import com.bytecat.algui.AlguiViews.AlguiViewInputBox; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.json.JSONException; +import org.json.JSONObject; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiViews.AlguiViewLine; +import java.io.File; + + public class AlguiWin2FA { + public static final String TAG = "AlguiWin2FA"; + // 保存 +private static final String KEY_USER = "user"; + public static String wy_user = ""; // 全局用户名 + Context aContext; + Activity aActivity; + private static AlguiWin2FA obj; + AlertDialog dialog;//对话框 + AlguiLinearLayout rootLayout;//根布局 + AlguiViewText title;//标题 + AlguiViewText text;//信息文本 + AlguiViewInputBox kamiInput;//输入框占位(防止不显示输入法) + AlguiLinearLayout layout;//容器布局 + AlguiViewLine hjm; + + + + // 获取 dialog 对象的方法 + public AlertDialog getByteDialog() { + return dialog; // 返回 AlertDialog 对象 + } + + // 获取 rootLayout 对象的方法 + public AlguiLinearLayout getByteRootLayout() { + return rootLayout; // 返回 AlguiLinearLayout 对象 + } + + // 获取 title 对象的方法 + public AlguiViewText getByteTitle() { + return title; // 返回 AlguiViewText 对象 + } + + // 获取 text 对象的方法 + public AlguiViewText getByteText() { + return text; // 返回 AlguiViewText 对象 + } + + // 获取 kamiInput 对象的方法 + public AlguiViewInputBox getByteKamiInput() { + return kamiInput; // 返回 AlguiViewInputBox 对象 + } + + // 获取 layout 对象的方法 + public AlguiLinearLayout getByteLayout() { + return layout; // 返回 AlguiLinearLayout 对象 + } + //单例访问器 + public static AlguiWin2FA Get(Context context, Activity activity) { + if (obj == null) { + obj = new AlguiWin2FA(context, activity); + } + return obj; + } + private AlguiWin2FA(Context context, Activity activity) { + aContext = context; + aActivity = activity; + init(); + } + private void init() { + //根布局 + rootLayout = new AlguiLinearLayout(aContext); + rootLayout.setCatSize(AlguiLinearLayout.LayoutParams.WRAP_CONTENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT); + rootLayout.setOrientation(LinearLayout.VERTICAL);//垂直 + rootLayout.setGravity(Gravity.CENTER_HORIZONTAL);//横向居中 + rootLayout.setCatBackColor(0xFFFFFFFF); + rootLayout.setCatRadiu(8); + rootLayout.setCatPadding(0, 0, 0, 10); + //标题 +String biaoti = "Connecting to the server ₍˄ ₗ ̫ ₗ ˄₎◞ ̑̑"; +String filePath1 ="/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; +File file = new File(filePath1); +if (file.exists()) { +biaoti = "正在连接服务器 ₍˄ ₗ ̫ ₗ ˄₎◞ ̑̑"; +} + title = new AlguiViewText(aContext, biaoti); + + + title.setCatTextGravity(Gravity.LEFT); + title.setCatTextSize(20); + title.setCatTextColor(0xFFFFFFFF); + title.setCatTextGlow(2, 0xFF000000); + title.setBackgroundColor(0xFFFFFFFF); + + //信息 + +String ttext = "Connecting, please wait patiently... (一-一)"; +String filePath2 ="/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; +File file2 = new File(filePath2); +if (file2.exists()) { +ttext = "正在连接,请耐心等待... (一-一)"; +} + + text = new AlguiViewText(aContext); + text.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT); + rootLayout.setGravity(Gravity.CENTER);//居中 + text.setCatText(ttext); + text.setCatTextIsLink(true); + text.setCatTextSize(12); + text.setCatMargins(20, 10, 20, 10); + + + + //输入框先占位 不然之后显示对话框后再次添加则获取不到输入法 +String kamii = "Please enter your account"; +String filePath3 ="/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; +File file3 = new File(filePath3); +if (file3.exists()) { +kamii = "请输入您的账号"; +} + + + + kamiInput = Input(kamii, "").setCatBackColor(0xFFFFFFFF).setCatInputTextColor(0x86000000).setCatBorder(0,0).setCatMargins(1,1,1,1).setCatSize(400,40).setCatTextSize(20); + kamiInput.setVisibility(View.GONE); + hjm =new AlguiViewLine(aContext); + hjm.setCatStyle(1); + hjm.setCatColor(0xFF000000); + hjm.setCatSize(1); + + + //容器布局 + layout = new AlguiLinearLayout(aContext); + layout.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.MATCH_PARENT); + + layout.setOrientation(LinearLayout.VERTICAL);//垂直 + + layout.setGravity(Gravity.RIGHT);//横向居中 + + layout.addView(Button("退出").setCatBackColor(0xFFFFFFFF).setCatTextColor(0xFF9198E5).setCatSize(50,30).setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + System.exit(0); + } + } + )); + + rootLayout.addView(title, text, kamiInput, layout); + + //对话框 + AlertDialog.Builder builder = new AlertDialog.Builder(aContext);//构建器 + builder.setView(rootLayout);//为对话框设置自定义布局 + dialog = builder.create();//创建对话框 + dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//设置对话框背景透明 (以便应用圆角) + //设置窗口类型 + if (aContext instanceof Activity) { + //对于上下文为活动时 窗口类型设置为应用级窗口 (无需悬浮窗权限) + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION); + } else { + //对于其它 则使用系统级后台全局窗口 (需要悬浮窗权限) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + //对于安卓8.0以上 + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); + } else { + //对于安卓8.0以下 + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + } + //申请悬浮窗权限 + AlguiToolPermission.getWindow(aContext); + } + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + //禁用返回键关闭对话框 + dialog.setCancelable(false); + setCatTitleBackImage(null); + + + } + + + + + //MD5哈希 + private String encodeMD5(String str) { + if (str == null) { + return "null"; + } + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(str.getBytes("UTF-8")); + byte messageDigest[] = md5.digest(); + StringBuilder hexString = new StringBuilder(); + for (byte b : messageDigest) { + hexString.append(String.format("%02X", b)); + } + return hexString.toString().toLowerCase(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + + //设置标题背景图片 + public AlguiWin2FA setCatTitleBackImage(final String Url_Base64_FilePath) { + if (Url_Base64_FilePath != null) { + title.setCatPadding(20, 20, 20, 20); + title.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, 70); + //确保在布局计算完成后才设置 + title.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + Drawable menuTopBackIMG;//菜单顶部布局背景图片 + public void update() { + int layoutWidth = title.getWidth(); + int layoutHeight = title.getHeight(); + + if (menuTopBackIMG != null) { + //如果是GIF图片直接设置 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P&&menuTopBackIMG instanceof AnimatedImageDrawable) { + title.setBackground((AnimatedImageDrawable) menuTopBackIMG); + } else { + //对于需要毛玻璃模糊 + //if (blurRadius > 0) + menuTopBackIMG = AlguiToolImage.psImageBlur(menuTopBackIMG, 55, aContext); + //对于非GIF图片进行缩放处理,图片宽超出布局宽则缩放到布局宽然后裁剪掉多余的高度部分 + Bitmap originalBitmap = AlguiToolImage.drawableToBitmap(menuTopBackIMG); + int originalWidth = originalBitmap.getWidth(); + int originalHeight = originalBitmap.getHeight(); + + // 图片与布局宽高一致直接设置 + if (layoutWidth == originalWidth && originalHeight == layoutHeight) { + title.setBackground(menuTopBackIMG); + } else { + //否则将图片宽度缩放为与布局宽度一致然后裁剪掉高度多余的部分 + //计算缩放比例 + float scale = (float) layoutWidth / originalWidth; + int scaledWidth = layoutWidth; + int scaledHeight = (int) (originalHeight * scale); + + //缩放图片 + Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, scaledWidth, scaledHeight, true); + + //如果缩放后的高度超出布局高度则裁剪掉超出的高度部分 + if (scaledHeight > layoutHeight) { + //计算裁剪区域 + int cropHeight = scaledHeight - layoutHeight; + int cropStartY = cropHeight / 2; + Bitmap croppedBitmap = Bitmap.createBitmap(scaledBitmap, 0, cropStartY, scaledWidth, layoutHeight); + menuTopBackIMG = new BitmapDrawable(aContext. getResources(), croppedBitmap); + title.setBackground(menuTopBackIMG); + } else { + //设置缩放后的图片为布局背景 + menuTopBackIMG = new BitmapDrawable(aContext.getResources(), scaledBitmap); + title.setBackground(menuTopBackIMG); + } + } + } + //if (Transparent0_255 >= 0) + //menuTopBackIMG.setAlpha(Transparent0_255); + } + } + @Override + public void onGlobalLayout() { + //移除监听器以避免重复调用 + title.getViewTreeObserver().removeOnGlobalLayoutListener(this); + menuTopBackIMG = AlguiToolImage.getImage(aContext, Url_Base64_FilePath, new AlguiCallback.Web(){ + //对于网络图像 + @Override + public void web(Message msg) { + switch (msg.what) { + case 200: + Object obj = msg.obj; + if (obj != null) { + if (obj instanceof Drawable) { + menuTopBackIMG = (Drawable)msg.obj; + update(); + } + } + break; + case 404: + Toast.makeText(aContext, "网络图片加载失败:服务器发生错误", Toast.LENGTH_SHORT).show(); + break; + case 651: + Toast.makeText(aContext, "网络图片加载失败:图片异常", Toast.LENGTH_SHORT).show(); + break; + } + } + }); + update(); + } + }); + } else { + title.setCatPadding(10, 10, 10, 10); + title.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT); + title.setCatBackColor(0xff294A7A); + } + + return this; + } + + //微验网络验证 + String wy_updateAPI="https://wy.llua.cn/api/?id=ini";//更新检测接口 + String wy_AnnouncementAPI="https://wy.llua.cn/api/?id=notice";//公告接口 + String wy_SingleCodeAPI="https://wy.llua.cn/api/?id=kmlogon";//单码连接接口 + String wy_kmDismissAPI="https://wy.llua.cn/api/?id=kmdismiss";//卡密解绑接口 + String wy_RemoteFieldAPI="https://wy.llua.cn/api/?id=getvalue";//远程变量接口 + String wy_appId;//应用ID + String wy_appCode;//应用版本号(检测更新) + int wy_okCode;//成功状态码 + String wy_appkey;//appkey密钥 + String wy_rc4_2;//rc4-2密钥 + String wy_kami="";//卡密 + //存储微验远程变量 + HashMap wy_remoteField = new HashMap<>(); + AlguiCallback.WY2FA wy2facall;//回调微验连接成功 + //设置应用ID + public AlguiWin2FA setCatWYAppID(String s) { + wy_appId = s; + return this; + } + //设置应用版本号 + public AlguiWin2FA setCatWYAppCode(String s) { + wy_appCode = s; + return this; + } + //设置应用密钥 + public AlguiWin2FA setCatWYAppKey(String s) { + wy_appkey = s; + return this; + } + //设置rc4-2密钥 + public AlguiWin2FA setCatWYRC4_2(String s) { + wy_rc4_2 = s; + return this; + } + //设置成功码 + public AlguiWin2FA setCatWYOkCode(int i) { + wy_okCode = i; + return this; + } + //添加一个远程变量名称 开始验证时连接成功后 将远程获取改变量名称的值 + public AlguiWin2FA addRemoteFieldName(String name) { + if (name != null) + wy_remoteField.put(name, ""); + return this; + } + //开始微验网络验证 传入连接成功后显示哪个窗口 + public void startWY(AlguiCallback.WY2FA wy2facall) { + this.wy2facall = wy2facall; + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + //禁用返回键关闭对话框 + dialog.setCancelable(false); + dialog.show(); + //sb(); + if (wy_appkey != null && wy_appId != null && wy_rc4_2 != null && wy_appCode != null) { + //自动输入上次保存的卡密 +wy_kami = (String) AlguiToolCache.getData(aContext, "kami", ""); +wy_user = (String) AlguiToolCache.getData(aContext, KEY_USER, ""); // 新增 + + wy_CheckUpdate(); + } + } + + private void sb(){ + final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + Runnable heartBeatTask = new Runnable() { + @Override + public void run() { + if(AlguiToolNetwork.isUnderAttack()){ + System.exit(0); + } + + } + }; + executorService.scheduleAtFixedRate(heartBeatTask, 0, 30, TimeUnit.SECONDS); + } + //微验检测更新 + private void wy_CheckUpdate() { + + AlguiToolNetwork.GET(wy_updateAPI + "&app=" + wy_appId, null , new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, wy_rc4_2, "UTF-8"); + } catch (UnsupportedEncodingException e) { + title.setCatText("更新检测失败[R]"); + text.setCatText("异常:" + e.getMessage()); + return; + } + /*{ + "code": 200, + "msg": { + "version": "我是版本号", + "app_update_show": "我是更新内容", + "app_update_url": "我是更新地址", + "app_update_must": "y"//强制更新 + }, + "time": 1655376684, + "check": "841692e22795cd8843df9dd505860a12" + }*/ + try { + //获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//从主代码体获取状态码 + if (code == 200) { + //服务器返回成功 + //从主代码体获取msg子代码体 + JSONObject msgObject = jsonObject.optJSONObject("msg"); + //从msg体获取数据 + String version = msgObject.optString("version");//版本号 + String updateContent = msgObject.optString("app_update_show");//更新内容 + final String updateUrl = msgObject.optString("app_update_url");//更新地址 + String isUpdate = msgObject.optString("app_update_must");//是否强制更新 + if (version != null && version.equals(wy_appCode)) { + //无需更新 + wy_Announcement(); + } else { + layout.remAllView();//清除容器视图 + //需要更新 + title.setCatText("发现新版本 " + "" + version + ""); + text.setCatText(updateContent); + layout.addView( + Button("立即更新").setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + AlguiToolNetwork.jumpWebSite(aActivity, updateUrl); + System.exit(0); + } + } + ) + ); + //如果不需要强制更新则加取消按钮 + if (!isUpdate.equals("y")) { + layout.addView( + Button("暂不更新").setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + wy_Announcement(); + } + } + ) + ); + } + + } + } else { + title.setCatText("更新检测失败[%d]", code); + } + + } catch (JSONException e) { + title.setCatText("更新检测失败[D]"); + text.setCatText("异常:" + e.getMessage()); + return; + } + } + + //请求失败 + @Override + public void onFailure(String error) { + title.setCatText("更新检测失败"); + text.setCatText(error); + } + }); + } + //微验公告 + + private void wy_Announcement() { + AlguiToolNetwork.GET(wy_AnnouncementAPI + "&app=" + wy_appId, null , new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, wy_rc4_2, "UTF-8"); + } catch (UnsupportedEncodingException e) { + //title.setCatText("公告获取失败[R]"); + //text.setCatText("异常:" + e.getMessage()); + wy_SingleCode(); + return; + } + /*{ + "code": 200, + "msg": { + "app_gg": "我是公告内容" + }, + "time": 1646296395, + "check": "ca614738a2cbe5f326ffe59c4b581840" + }*/ + try { + //获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//从主代码体获取状态码 + if (code != 200) {wy_SingleCode();return;} + //从主代码体获取msg子代码体 + JSONObject msgObject = jsonObject.optJSONObject("msg"); + //从msg体获取数据 + String str = msgObject.optString("app_gg");//公告内容 + layout.remAllView();//清除容器视图 + wy_SingleCode(); + + text.setCatText(str); + + + } catch (JSONException e) { + //title.setCatText("公告获取失败[D]"); + //text.setCatText("异常:" + e.getMessage()); + wy_SingleCode(); + } + } + //请求失败 + @Override + public void onFailure(String error) { + //title.setCatText("公告获取失败"); + //text.setCatText(error); + wy_SingleCode(); + } + }); + } + + //微验单码连接 + private void wy_SingleCode() { + + + //一言 + text.setCatText("永远相信美好的事情即将发生"); + layout.remAllView();//清除容器视图 + + +title.setCatText("TrosCore").setTextColor(0xFF9198E5); +title .setBackgroundColor(0xFFFFFFFF); +title.setCatTextSize(30); +title.setCatMargins(2,2,2,2); + +//显示输入框 + kamiInput.setVisibility(View.VISIBLE); + + // 用户名输入框(全局变量实时同步) +String kamiii = "Please enter your user name"; +String filePath7 ="/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; +File file7 = new File(filePath7); +if (file7.exists()) { +kamiii = "请输入您的用户名(自定义)"; +} + + final AlguiViewInputBox userInput = Input(kamiii, "") + .setCatBackColor(0xFFFFFFFF) + .setCatInputTextColor(0x86000000) + .setCatBorder(0, 0) + .setCatMargins(1, 1, 1, 1) + .setCatSize(400, 40) + .setCatTextSize(20); + userInput.setCatCallback(new AlguiCallback.Input() { + public void start(String text) { wy_user = text; } + public void update(String text) { wy_user = text; } + public void end(String text) { wy_user = text; } + }); + rootLayout.addView(userInput, rootLayout.indexOfChild(kamiInput) + 1); + + + kamiInput.setCatInputText(wy_kami); + kamiInput.setCatCallback(new AlguiCallback.Input(){ + public void start(String text) { + wy_kami = text; + + } + public void update(String text) { + wy_kami = text; + } + public void end(String text) { + wy_kami = text; + } + } + + ); + + + hjm.setCatStyle(0); + hjm.setCatMargins(10,10,10,10); + hjm.setCatColor(0xFF000000); + hjm.setCatSize(1); + + + AlguiViewLine Line=new AlguiViewLine(aContext).setCatStyle(0).setCatMargins(1,1,1,10) + .setCatColor(0xFF9198E5) + .setCatParentLayout(layout).setCatSize(4) + ; + + + + +String llogin = "Login"; +String filePath5 ="/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; +File file4 = new File(filePath5); +if (file4.exists()) { +llogin = "登录"; +} + + layout.addView( + Button(llogin).setCatBackColor(0xFFFFFFFF).setCatTextColor(0xFF9198E5).setCatSize(50,30).setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + final AlguiViewText text=new AlguiViewText(aContext); + + final String si = AlguiToolNetwork.getSeries(wy_appId, "836756926f"); + final int sc = Integer.parseInt(AlguiToolNetwork.getSeries(wy_okCode + "", "8e6d599a6560478569")); + final String sk = AlguiToolNetwork.getSeries(wy_appkey, "843219e9681f45d6261117e9ca2d17"); + final String sr = AlguiToolNetwork.getSeries(wy_rc4_2, "8f2f23906e2148f8303303cafa1505"); + + + //获取机器码 + final String markcode =android.provider.Settings.Secure.getString(aContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);; + //获取当前时间戳 + final Long time = System.currentTimeMillis() / 1000; + + //对数据进行签名 + String signs = "kami=" + wy_kami;//提交卡密 + signs += "&markcode=" + markcode;//提交机器码 + signs += "&t=" + time;//提交时间戳 + signs += "&" + sk;//提交APP密钥 + signs = encodeMD5(signs);//对数据进行哈希 + + //构造请求数据 + String body=wy_SingleCodeAPI; + body += "&app=" + si;//提交APPID + body += "&kami=" + wy_kami;//提交卡密 + body += "&markcode=" + markcode;//提交机器码 + body += "&t=" + time;//提交时间戳 + body += "&sign=" + signs;//提交签名 + + //利用机器码和app密钥生成随机标识符 + String random = UUID.randomUUID().toString().replace("-", "") + sk + markcode; + + try { + //加密请求数据 + String data = "data=" + AlguiToolRC4.encryRC4String(body, sr, "UTF-8"); + + //开始请求 + + AlguiToolNetwork.POST(body + "&app=" + si, data + "&value=" + random, new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, sr, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常:" + e.getMessage()); + POST(); + return; + } + /* { + "code": 200, + "msg": { + "id": 983857, + "kmtype": "卡密", + "ktype": "code", + "vip": 1667229718 + }, + "time": 1666676640, + "check": "bbfe2118db1862bbab0626290ecd8dc4", + "check2": "f44034aaab42996304c26ab579777444" + }*/ + try { + //主代码体获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//获取状态码 + String check=jsonObject.optString("check");//校验密钥 + Long timee=jsonObject.optLong("time");//服务器时间戳 + + + if (check.equals(encodeMD5(timee.toString() + sk + si))) { + //非法操作 + // AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:非法操作"); + POST(); + } else if (timee - time > 30 || timee - time < -30) { + //数据过期 + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:数据已过期"); + POST(); + } else if (code == sc) { + //连接成功 + //msg代码体获取数据 + JSONObject msgObject = jsonObject.optJSONObject("msg");//从主代码体获取msg子代码体 + final Long vip=msgObject.optLong("vip");//到期时间 + //格式时间戳 + GregorianCalendar gc=new GregorianCalendar(); + gc.setTimeInMillis(vip * 1000); + SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");//到期时间格式:yyyy-MM-dd(年月日) HH:mm:ss(时分秒) EEEE(星期几) EE(周几) + final String str = df.format(gc.getTime()); + + + AlguiToolCache.saveData(aContext, "kami", wy_kami);//卡密 +AlguiToolCache.saveData(aContext, KEY_USER, wy_user); + if (wy2facall != null) + wy2facall.success(wy_kami, str, wy_remoteField); + + //开始心跳验证 + final Handler mainHandler = new Handler(Looper.getMainLooper());//保存主线程 + final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + Runnable heartBeatTask = new Runnable() { + @Override + public void run() { + + //获取服务器时间 + AlguiToolNetwork.GET("https://vv.video.qq.com/checktime?otype=json", null, new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(final String response) { + + try { + + String jsonContent = response.substring(response.indexOf("{"));//获取{开始之后的所有字符串 + JSONObject jsonObject = new JSONObject(jsonContent); + Long serverTime = jsonObject.getLong("t");//服务器时间戳 + + + // 检查服务器时间戳是否大于到期时间戳 + if (serverTime > vip) { + //切换到主线程更新 + mainHandler.post(new Runnable() { + @Override + public void run() { + + + layout.remAllView();//清除容器视图 + + wy_SingleCode(); + text.setCatText("卡密已到期,请重新连接或续费!"); + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + dialog.show(); + + } + }); + + //停止定时任务 + executorService.shutdownNow(); + } + } catch (JSONException e) { + e.printStackTrace(); + + } + } + + @Override + public void onFailure(String error) { + + } + }); + + } + }; + //每隔30秒执行一次心跳请求 + executorService.scheduleAtFixedRate(heartBeatTask, 0, 30, TimeUnit.SECONDS); + dialog.dismiss(); + } else { + //其他情况 + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:" + jsonObject.getString("msg")); + POST(); + } + } catch (JSONException e) { + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常:" + e.getMessage()); + POST(); + } + } + //请求失败 + @Override + public void onFailure(String error) { + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败" + error); + POST(); + } + }); + } catch (UnsupportedEncodingException e) { + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常" + e.getMessage()); + POST(); + } + + + } + } + ) + ); + + +String eexit = "Exit"; +String filePath6 ="/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; +File file5 = new File(filePath6); +if (file5.exists()) { +eexit = "退出"; +} + + layout.addView(Button(eexit).setCatBackColor(0xFFFFFFFF).setCatTextColor(0xFF9198E5).setCatSize(50,30).setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + System.exit(0); + } + } + )); + + + } + + + private void GET() { + //获取机器码 + String markcode =android.provider.Settings.Secure.getString(aContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);; + //获取当前时间戳 + final Long time = System.currentTimeMillis() / 1000; + + //对数据进行签名 + String signs = "kami=" + wy_kami;//提交卡密 + signs += "&markcode=" + markcode;//提交机器码 + signs += "&t=" + time;//提交时间戳 + signs += "&" + wy_appkey;//提交APP密钥 + signs = encodeMD5(signs);//对数据进行哈希 + + //构造请求数据 + String body=wy_kmDismissAPI; + body += "&app=" + wy_appId;//提交APPID + body += "&kami=" + wy_kami;//提交卡密 + body += "&markcode=" + markcode;//提交机器码 + body += "&t=" + time;//提交时间戳 + body += "&sign=" + signs;//提交签名 + + //利用机器码和app密钥生成随机标识符 + String random = UUID.randomUUID().toString().replace("-", "") + wy_appkey + markcode; + + + //加密请求数据 + try { + String data = "data=" + AlguiToolRC4.encryRC4String(body, wy_rc4_2, "UTF-8"); + AlguiToolNetwork.POST(body + "&app=" + wy_appId, data + "&value=" + random , new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, wy_rc4_2, "UTF-8"); + } catch (UnsupportedEncodingException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败 异常:" + e.getMessage()); + return; + } + /* + { + "code": 200, + "msg": { + "num": "3", + }, + "time": 1614689850, + "check": "07ed8fe3ecb9aea3817c336037fdbb52" + } + */ + try { + //获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//从主代码体获取状态码 + String Message=jsonObject.getString("msg"); + + if (code == 200) {//解绑成功 + JSONObject json = new JSONObject(Message); + int num = json.getInt("num"); + + text.setCatText("卡密解绑成功!还剩" + "" + num + "" + "次解绑机会"); + } else { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败: " + Message); + } + } catch (JSONException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败 异常:" + e.getMessage()); + } + } + //请求失败 + @Override + public void onFailure(String error) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败 " + error); + } + }); + } catch (UnsupportedEncodingException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败 异常" + e.getMessage()); + } + + } + + private void POST() { + //获取机器码 + final String markcode =android.provider.Settings.Secure.getString(aContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); + //获取当前时间戳 + final Long time = System.currentTimeMillis() / 1000; + + //对数据进行签名 + String signs = "kami=" + wy_kami;//提交卡密 + signs += "&markcode=" + markcode;//提交机器码 + signs += "&t=" + time;//提交时间戳 + signs += "&" + wy_appkey;//提交APP密钥 + signs = encodeMD5(signs);//对数据进行哈希 + + //构造请求数据 + String body=wy_SingleCodeAPI; + body += "&app=" + wy_appId;//提交APPID + body += "&kami=" + wy_kami;//提交卡密 + body += "&markcode=" + markcode;//提交机器码 + body += "&t=" + time;//提交时间戳 + body += "&sign=" + signs;//提交签名 + + //利用机器码和app密钥生成随机标识符 + String random = UUID.randomUUID().toString().replace("-", "") + wy_appkey + markcode; + + try { + //加密请求数据 + String data = "data=" + AlguiToolRC4.encryRC4String(body, wy_rc4_2, "UTF-8"); + + //开始请求 + AlguiToolNetwork.POST(body + "&app=" + wy_appId, data + "&value=" + random, new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, wy_rc4_2, "UTF-8"); + } catch (UnsupportedEncodingException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常:" + e.getMessage()); + return; + } + /* { + "code": 200, + "msg": { + "id": 983857, + "kmtype": "卡密", + "ktype": "code", + "vip": 1667229718 + }, + "time": 1666676640, + "check": "bbfe2118db1862bbab0626290ecd8dc4", + "check2": "f44034aaab42996304c26ab579777444" + }*/ + try { + //主代码体获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//获取状态码 + String check=jsonObject.optString("check");//校验密钥 + Long timee=jsonObject.optLong("time");//服务器时间戳 + + + if (check.equals(encodeMD5(timee.toString() + wy_appkey + wy_appId))) { + //非法操作 + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:非法操作"); + } else if (timee - time > 30 || timee - time < -30) { + //数据过期 + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:数据已过期"); + } else if (code == wy_okCode) { + //连接成功 + + //msg代码体获取数据 + JSONObject msgObject = jsonObject.optJSONObject("msg");//从主代码体获取msg子代码体 + final Long vip=msgObject.optLong("vip");//到期时间 + //格式时间戳 + GregorianCalendar gc=new GregorianCalendar(); + gc.setTimeInMillis(vip * 1000); + SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");//到期时间格式:yyyy-MM-dd(年月日) HH:mm:ss(时分秒) EEEE(星期几) EE(周几) + final String str = df.format(gc.getTime()); + + + AlguiToolCache.saveData(aContext, "kami", wy_kami);//保存卡密 +AlguiToolCache.saveData(aContext, KEY_USER, wy_user); + + if (wy_remoteField.isEmpty()) { + if (wy2facall != null) + wy2facall.success(wy_kami, str, wy_remoteField); + } else { + if (wy2facall != null) { + new AsyncTask>() { + @Override + protected HashMap doInBackground(Void... voids) { + + //开始获取远程变量 + + for (Map.Entry entry : wy_remoteField.entrySet()) { + final String key = entry.getKey(); + if (key != null) { + //对数据进行签名 + String signs = "kami=" + wy_kami;//提交卡密 + signs += "&markcode=" + markcode;//提交机器码 + signs += "&t=" + time;//提交时间戳 + signs += "&value" + key; + signs += "&" + wy_appkey;//提交APP密钥 + signs = encodeMD5(signs);//对数据进行哈希 + + //构造请求数据 + String body=wy_RemoteFieldAPI; + body += "&app=" + wy_appId;//提交APPID + body += "&kami=" + wy_kami;//提交卡密 + body += "&markcode=" + markcode;//提交机器码 + body += "&t=" + time;//提交时间戳 + body += "&value" + key; + body += "&sign=" + signs;//提交签名 + + //利用机器码和app密钥生成随机标识符 + //String random = UUID.randomUUID().toString().replace("-", "") + wy_appkey + markcode; + + + //加密请求数据 + try { + String data = "data=" + AlguiToolRC4.encryRC4String(body, wy_rc4_2, "UTF-8"); + //开始请求 + String r = AlguiToolRC4.decryRC4(AlguiToolNetwork.UrlPost(body + "&app=" + wy_appId, data + "&value=" + key), wy_rc4_2, "UTF-8"); + /* + { + "code": 200, + "msg": "我是远程变量内容", + "time": 114514114514, + "check": "bbfe2118db1862bbab0626290ecd8dc4", + "check2": "f44034aaab42996304c26ab579777444" + } + */ + try { + JSONObject jsonObject = new JSONObject(r); + if (jsonObject.getInt("code") == 200) { + String Message=jsonObject.getString("msg");//内容头部 + JSONObject messageObject=new JSONObject(Message); + String v=messageObject.getString("msg");//变量值 + + if (v != null) { + + wy_remoteField.put(key, v); + } + } + + } catch (JSONException e) {} + + + } catch (UnsupportedEncodingException e) {} + } + + } + return wy_remoteField; + } + + @Override + protected void onPostExecute(HashMap result) { + wy2facall.success(wy_kami, str, wy_remoteField); + } + }.execute(); + } + } + + //开始心跳验证 + final Handler mainHandler = new Handler(Looper.getMainLooper());//保存主线程 + final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + Runnable heartBeatTask = new Runnable() { + @Override + public void run() { + + //获取服务器时间 + AlguiToolNetwork.GET("https://vv.video.qq.com/checktime?otype=json", null, new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(final String response) { + + try { + + String jsonContent = response.substring(response.indexOf("{"));//获取{开始之后的所有字符串 + JSONObject jsonObject = new JSONObject(jsonContent); + Long serverTime = jsonObject.getLong("t");//服务器时间戳 + + + // 检查服务器时间戳是否大于到期时间戳 + if (serverTime > vip) { + //切换到主线程更新 + mainHandler.post(new Runnable() { + @Override + public void run() { + + + layout.remAllView();//清除容器视图 + + wy_SingleCode(); + text.setCatText("卡密已到期,请重新连接或续费!"); + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + dialog.show(); + + } + }); + + //停止定时任务 + executorService.shutdownNow(); + } + } catch (JSONException e) { + e.printStackTrace(); + + } + } + + @Override + public void onFailure(String error) { + + } + }); + } + }; + //每隔30秒执行一次心跳请求 + executorService.scheduleAtFixedRate(heartBeatTask, 0, 30, TimeUnit.SECONDS); + dialog.dismiss(); + + + } else { + //其他情况 + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:" + jsonObject.getString("msg")); + } + } catch (JSONException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常:" + e.getMessage()); + + } + } + //请求失败 + @Override + public void onFailure(String error) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败" + error); + } + }); + } catch (UnsupportedEncodingException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常" + e.getMessage()); + } + + } + + public void initNet() { + final String si = AlguiToolNetwork.getSeries(wy_appId, "836756926f"); + final String sk = AlguiToolNetwork.getSeries(wy_appkey, "843219e9681f45d6261117e9ca2d17"); + final String sr = AlguiToolNetwork.getSeries(wy_rc4_2, "8f2f23906e2148f8303303cafa1505"); + final String av = "av"; + final String markcode = android.provider.Settings.Secure.getString(aContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);; + final Long time = System.currentTimeMillis() / 1000; + new AsyncTask>() { + @Override + protected HashMap doInBackground(Void... voids) { + + String signs = "kami=" + av; + signs += "&markcode=" + markcode; + signs += "&t=" + time; + signs += "&value" + av; + signs += "&" + sk; + signs = encodeMD5(signs); + + String body = wy_RemoteFieldAPI; + body += "&app=" + si; + body += "&kami=" + av; + body += "&markcode=" + markcode; + body += "&t=" + time; + body += "&value" + av; + body += "&sign=" + signs; + + try { + String data = "data=" + AlguiToolRC4.encryRC4String(body, sr, "UTF-8"); + + String r = AlguiToolRC4.decryRC4(AlguiToolNetwork.UrlPost(body + "&app=" + si, data + "&value=" + av), sr, "UTF-8"); + + try { + JSONObject jsonObject = new JSONObject(r); + if (jsonObject.getInt("code") == 200) { + String Message = jsonObject.getString("msg"); + JSONObject messageObject = new JSONObject(Message); + String v = messageObject.getString("msg"); + if (!Boolean.valueOf(v)) {System.exit(0);} + } + } catch (JSONException e) {} + } catch (UnsupportedEncodingException e) {} + + return null; + } + + @Override + protected void onPostExecute(HashMap result) { + + } + }.execute(); + + } + + + + //输入框 + private AlguiViewInputBox Input(CharSequence hint, CharSequence text) { + AlguiViewInputBox input = new AlguiViewInputBox(aContext); + input.setCatButtonText(null); + input.setCatInputHint(hint); + input.setCatInputText(text); + input.setCatTextSize(13); + input.setCatMargins(20, 0, 20, 10); + input.setCatBorder(1, 0xff274A72); + input.setCatRadiu(4); + + return input; + } + //按钮 + private AlguiViewButton Button(CharSequence text, Object... args) { + AlguiViewButton button = new AlguiViewButton(aContext); + button.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT); + button.setCatText(text, args); + button.setCatTextSize(15); + button.setCatMargins(20, 0, 20, 10); + button.setCatRadiu(4); + + return button; + } + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWin2FA.java.bak b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWin2FA.java.bak new file mode 100644 index 0000000..4c8a910 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWin2FA.java.bak @@ -0,0 +1,1267 @@ +package com.bytecat.algui.AlguiWindows; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/29 17:47 + * @Describe 网络验证窗口 + */ +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.drawable.AnimatedImageDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.icu.text.SimpleDateFormat; +import android.icu.util.GregorianCalendar; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.view.Gravity; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.Toast; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import com.bytecat.algui.AlguiTools.AlguiToolCache; +import com.bytecat.algui.AlguiTools.AlguiToolImage; +import com.bytecat.algui.AlguiTools.AlguiToolNetwork; +import com.bytecat.algui.AlguiTools.AlguiToolPermission; +import com.bytecat.algui.AlguiTools.AlguiToolRC4; +import com.bytecat.algui.AlguiViews.AlguiLinearLayout; +import com.bytecat.algui.AlguiViews.AlguiViewButton; +import com.bytecat.algui.AlguiViews.AlguiViewInputBox; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.json.JSONException; +import org.json.JSONObject; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiViews.AlguiViewLine; +import java.io.File; + + public class AlguiWin2FA { + public static final String TAG = "AlguiWin2FA"; + // 保存 +private static final String KEY_USER = "user"; + public static String wy_user = ""; // 全局用户名 + Context aContext; + Activity aActivity; + private static AlguiWin2FA obj; + AlertDialog dialog;//对话框 + AlguiLinearLayout rootLayout;//根布局 + AlguiViewText title;//标题 + AlguiViewText text;//信息文本 + AlguiViewInputBox kamiInput;//输入框占位(防止不显示输入法) + AlguiLinearLayout layout;//容器布局 + AlguiViewLine hjm; + + + + // 获取 dialog 对象的方法 + public AlertDialog getByteDialog() { + return dialog; // 返回 AlertDialog 对象 + } + + // 获取 rootLayout 对象的方法 + public AlguiLinearLayout getByteRootLayout() { + return rootLayout; // 返回 AlguiLinearLayout 对象 + } + + // 获取 title 对象的方法 + public AlguiViewText getByteTitle() { + return title; // 返回 AlguiViewText 对象 + } + + // 获取 text 对象的方法 + public AlguiViewText getByteText() { + return text; // 返回 AlguiViewText 对象 + } + + // 获取 kamiInput 对象的方法 + public AlguiViewInputBox getByteKamiInput() { + return kamiInput; // 返回 AlguiViewInputBox 对象 + } + + // 获取 layout 对象的方法 + public AlguiLinearLayout getByteLayout() { + return layout; // 返回 AlguiLinearLayout 对象 + } + //单例访问器 + public static AlguiWin2FA Get(Context context, Activity activity) { + if (obj == null) { + obj = new AlguiWin2FA(context, activity); + } + return obj; + } + private AlguiWin2FA(Context context, Activity activity) { + aContext = context; + aActivity = activity; + init(); + } + private void init() { + //根布局 + rootLayout = new AlguiLinearLayout(aContext); + rootLayout.setCatSize(AlguiLinearLayout.LayoutParams.WRAP_CONTENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT); + rootLayout.setOrientation(LinearLayout.VERTICAL);//垂直 + rootLayout.setGravity(Gravity.CENTER_HORIZONTAL);//横向居中 + rootLayout.setCatBackColor(0xFFFFFFFF); + rootLayout.setCatRadiu(8); + rootLayout.setCatPadding(0, 0, 0, 10); + //标题 +String biaoti = "Connecting to the server ₍˄ ₗ ̫ ₗ ˄₎◞ ̑̑"; +String filePath1 ="/sdcard/Android/data/com.vortex.celestial/files/"; +File file = new File(filePath1); +if (file.exists()) { +biaoti = "正在连接服务器 ₍˄ ₗ ̫ ₗ ˄₎◞ ̑̑"; +} + title = new AlguiViewText(aContext, biaoti); + + + title.setCatTextGravity(Gravity.LEFT); + title.setCatTextSize(20); + title.setCatTextColor(0xFFFFFFFF); + title.setCatTextGlow(2, 0xFF000000); + title.setBackgroundColor(0xFFFFFFFF); + + //信息 + +String ttext = "Connecting, please wait patiently... (一-一)"; +String filePath2 ="/sdcard/Android/data/com.vortex.celestial/files/"; +File file2 = new File(filePath2); +if (file2.exists()) { +ttext = "正在连接,请耐心等待... (一-一)"; +} + + text = new AlguiViewText(aContext); + text.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT); + rootLayout.setGravity(Gravity.CENTER);//居中 + text.setCatText(ttext); + text.setCatTextIsLink(true); + text.setCatTextSize(12); + text.setCatMargins(20, 10, 20, 10); + + + + //输入框先占位 不然之后显示对话框后再次添加则获取不到输入法 +String kamii = "Please enter your account"; +String filePath3 ="/sdcard/Android/data/com.vortex.celestial/files/"; +File file3 = new File(filePath3); +if (file3.exists()) { +kamii = "请输入您的账号"; +} + + + + kamiInput = Input(kamii, "").setCatBackColor(0xFFFFFFFF).setCatInputTextColor(0x86000000).setCatBorder(0,0).setCatMargins(1,1,1,1).setCatSize(400,40).setCatTextSize(20); + kamiInput.setVisibility(View.GONE); + hjm =new AlguiViewLine(aContext); + hjm.setCatStyle(1); + hjm.setCatColor(0xFF000000); + hjm.setCatSize(1); + + + //容器布局 + layout = new AlguiLinearLayout(aContext); + layout.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.MATCH_PARENT); + + layout.setOrientation(LinearLayout.VERTICAL);//垂直 + + layout.setGravity(Gravity.RIGHT);//横向居中 + + layout.addView(Button("退出").setCatBackColor(0xFFFFFFFF).setCatTextColor(0xFF9198E5).setCatSize(50,30).setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + System.exit(0); + } + } + )); + + rootLayout.addView(title, text, kamiInput, layout); + + //对话框 + AlertDialog.Builder builder = new AlertDialog.Builder(aContext);//构建器 + builder.setView(rootLayout);//为对话框设置自定义布局 + dialog = builder.create();//创建对话框 + dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//设置对话框背景透明 (以便应用圆角) + //设置窗口类型 + if (aContext instanceof Activity) { + //对于上下文为活动时 窗口类型设置为应用级窗口 (无需悬浮窗权限) + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION); + } else { + //对于其它 则使用系统级后台全局窗口 (需要悬浮窗权限) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + //对于安卓8.0以上 + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); + } else { + //对于安卓8.0以下 + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + } + //申请悬浮窗权限 + AlguiToolPermission.getWindow(aContext); + } + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + //禁用返回键关闭对话框 + dialog.setCancelable(false); + setCatTitleBackImage(null); + + + } + + + + + //MD5哈希 + private String encodeMD5(String str) { + if (str == null) { + return "null"; + } + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(str.getBytes("UTF-8")); + byte messageDigest[] = md5.digest(); + StringBuilder hexString = new StringBuilder(); + for (byte b : messageDigest) { + hexString.append(String.format("%02X", b)); + } + return hexString.toString().toLowerCase(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + + //设置标题背景图片 + public AlguiWin2FA setCatTitleBackImage(final String Url_Base64_FilePath) { + if (Url_Base64_FilePath != null) { + title.setCatPadding(20, 20, 20, 20); + title.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, 70); + //确保在布局计算完成后才设置 + title.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + Drawable menuTopBackIMG;//菜单顶部布局背景图片 + public void update() { + int layoutWidth = title.getWidth(); + int layoutHeight = title.getHeight(); + + if (menuTopBackIMG != null) { + //如果是GIF图片直接设置 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P&&menuTopBackIMG instanceof AnimatedImageDrawable) { + title.setBackground((AnimatedImageDrawable) menuTopBackIMG); + } else { + //对于需要毛玻璃模糊 + //if (blurRadius > 0) + menuTopBackIMG = AlguiToolImage.psImageBlur(menuTopBackIMG, 55, aContext); + //对于非GIF图片进行缩放处理,图片宽超出布局宽则缩放到布局宽然后裁剪掉多余的高度部分 + Bitmap originalBitmap = AlguiToolImage.drawableToBitmap(menuTopBackIMG); + int originalWidth = originalBitmap.getWidth(); + int originalHeight = originalBitmap.getHeight(); + + // 图片与布局宽高一致直接设置 + if (layoutWidth == originalWidth && originalHeight == layoutHeight) { + title.setBackground(menuTopBackIMG); + } else { + //否则将图片宽度缩放为与布局宽度一致然后裁剪掉高度多余的部分 + //计算缩放比例 + float scale = (float) layoutWidth / originalWidth; + int scaledWidth = layoutWidth; + int scaledHeight = (int) (originalHeight * scale); + + //缩放图片 + Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, scaledWidth, scaledHeight, true); + + //如果缩放后的高度超出布局高度则裁剪掉超出的高度部分 + if (scaledHeight > layoutHeight) { + //计算裁剪区域 + int cropHeight = scaledHeight - layoutHeight; + int cropStartY = cropHeight / 2; + Bitmap croppedBitmap = Bitmap.createBitmap(scaledBitmap, 0, cropStartY, scaledWidth, layoutHeight); + menuTopBackIMG = new BitmapDrawable(aContext. getResources(), croppedBitmap); + title.setBackground(menuTopBackIMG); + } else { + //设置缩放后的图片为布局背景 + menuTopBackIMG = new BitmapDrawable(aContext.getResources(), scaledBitmap); + title.setBackground(menuTopBackIMG); + } + } + } + //if (Transparent0_255 >= 0) + //menuTopBackIMG.setAlpha(Transparent0_255); + } + } + @Override + public void onGlobalLayout() { + //移除监听器以避免重复调用 + title.getViewTreeObserver().removeOnGlobalLayoutListener(this); + menuTopBackIMG = AlguiToolImage.getImage(aContext, Url_Base64_FilePath, new AlguiCallback.Web(){ + //对于网络图像 + @Override + public void web(Message msg) { + switch (msg.what) { + case 200: + Object obj = msg.obj; + if (obj != null) { + if (obj instanceof Drawable) { + menuTopBackIMG = (Drawable)msg.obj; + update(); + } + } + break; + case 404: + Toast.makeText(aContext, "网络图片加载失败:服务器发生错误", Toast.LENGTH_SHORT).show(); + break; + case 651: + Toast.makeText(aContext, "网络图片加载失败:图片异常", Toast.LENGTH_SHORT).show(); + break; + } + } + }); + update(); + } + }); + } else { + title.setCatPadding(10, 10, 10, 10); + title.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT); + title.setCatBackColor(0xff294A7A); + } + + return this; + } + + //微验网络验证 + String wy_updateAPI="https://wy.llua.cn/api/?id=ini";//更新检测接口 + String wy_AnnouncementAPI="https://wy.llua.cn/api/?id=notice";//公告接口 + String wy_SingleCodeAPI="https://wy.llua.cn/api/?id=kmlogon";//单码连接接口 + String wy_kmDismissAPI="https://wy.llua.cn/api/?id=kmdismiss";//卡密解绑接口 + String wy_RemoteFieldAPI="https://wy.llua.cn/api/?id=getvalue";//远程变量接口 + String wy_appId;//应用ID + String wy_appCode;//应用版本号(检测更新) + int wy_okCode;//成功状态码 + String wy_appkey;//appkey密钥 + String wy_rc4_2;//rc4-2密钥 + String wy_kami="";//卡密 + //存储微验远程变量 + HashMap wy_remoteField = new HashMap<>(); + AlguiCallback.WY2FA wy2facall;//回调微验连接成功 + //设置应用ID + public AlguiWin2FA setCatWYAppID(String s) { + wy_appId = s; + return this; + } + //设置应用版本号 + public AlguiWin2FA setCatWYAppCode(String s) { + wy_appCode = s; + return this; + } + //设置应用密钥 + public AlguiWin2FA setCatWYAppKey(String s) { + wy_appkey = s; + return this; + } + //设置rc4-2密钥 + public AlguiWin2FA setCatWYRC4_2(String s) { + wy_rc4_2 = s; + return this; + } + //设置成功码 + public AlguiWin2FA setCatWYOkCode(int i) { + wy_okCode = i; + return this; + } + //添加一个远程变量名称 开始验证时连接成功后 将远程获取改变量名称的值 + public AlguiWin2FA addRemoteFieldName(String name) { + if (name != null) + wy_remoteField.put(name, ""); + return this; + } + //开始微验网络验证 传入连接成功后显示哪个窗口 + public void startWY(AlguiCallback.WY2FA wy2facall) { + this.wy2facall = wy2facall; + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + //禁用返回键关闭对话框 + dialog.setCancelable(false); + dialog.show(); + //sb(); + if (wy_appkey != null && wy_appId != null && wy_rc4_2 != null && wy_appCode != null) { + //自动输入上次保存的卡密 +wy_kami = (String) AlguiToolCache.getData(aContext, "kami", ""); +wy_user = (String) AlguiToolCache.getData(aContext, KEY_USER, ""); // 新增 + + wy_CheckUpdate(); + } + } + + private void sb(){ + final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + Runnable heartBeatTask = new Runnable() { + @Override + public void run() { + if(AlguiToolNetwork.isUnderAttack()){ + System.exit(0); + } + + } + }; + executorService.scheduleAtFixedRate(heartBeatTask, 0, 30, TimeUnit.SECONDS); + } + //微验检测更新 + private void wy_CheckUpdate() { + + AlguiToolNetwork.GET(wy_updateAPI + "&app=" + wy_appId, null , new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, wy_rc4_2, "UTF-8"); + } catch (UnsupportedEncodingException e) { + title.setCatText("更新检测失败[R]"); + text.setCatText("异常:" + e.getMessage()); + return; + } + /*{ + "code": 200, + "msg": { + "version": "我是版本号", + "app_update_show": "我是更新内容", + "app_update_url": "我是更新地址", + "app_update_must": "y"//强制更新 + }, + "time": 1655376684, + "check": "841692e22795cd8843df9dd505860a12" + }*/ + try { + //获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//从主代码体获取状态码 + if (code == 200) { + //服务器返回成功 + //从主代码体获取msg子代码体 + JSONObject msgObject = jsonObject.optJSONObject("msg"); + //从msg体获取数据 + String version = msgObject.optString("version");//版本号 + String updateContent = msgObject.optString("app_update_show");//更新内容 + final String updateUrl = msgObject.optString("app_update_url");//更新地址 + String isUpdate = msgObject.optString("app_update_must");//是否强制更新 + if (version != null && version.equals(wy_appCode)) { + //无需更新 + wy_Announcement(); + } else { + layout.remAllView();//清除容器视图 + //需要更新 + title.setCatText("发现新版本 " + "" + version + ""); + text.setCatText(updateContent); + layout.addView( + Button("立即更新").setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + AlguiToolNetwork.jumpWebSite(aActivity, updateUrl); + System.exit(0); + } + } + ) + ); + //如果不需要强制更新则加取消按钮 + if (!isUpdate.equals("y")) { + layout.addView( + Button("暂不更新").setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + wy_Announcement(); + } + } + ) + ); + } + + } + } else { + title.setCatText("更新检测失败[%d]", code); + } + + } catch (JSONException e) { + title.setCatText("更新检测失败[D]"); + text.setCatText("异常:" + e.getMessage()); + return; + } + } + + //请求失败 + @Override + public void onFailure(String error) { + title.setCatText("更新检测失败"); + text.setCatText(error); + } + }); + } + //微验公告 + + private void wy_Announcement() { + AlguiToolNetwork.GET(wy_AnnouncementAPI + "&app=" + wy_appId, null , new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, wy_rc4_2, "UTF-8"); + } catch (UnsupportedEncodingException e) { + //title.setCatText("公告获取失败[R]"); + //text.setCatText("异常:" + e.getMessage()); + wy_SingleCode(); + return; + } + /*{ + "code": 200, + "msg": { + "app_gg": "我是公告内容" + }, + "time": 1646296395, + "check": "ca614738a2cbe5f326ffe59c4b581840" + }*/ + try { + //获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//从主代码体获取状态码 + if (code != 200) {wy_SingleCode();return;} + //从主代码体获取msg子代码体 + JSONObject msgObject = jsonObject.optJSONObject("msg"); + //从msg体获取数据 + String str = msgObject.optString("app_gg");//公告内容 + layout.remAllView();//清除容器视图 + wy_SingleCode(); + + text.setCatText(str); + + + } catch (JSONException e) { + //title.setCatText("公告获取失败[D]"); + //text.setCatText("异常:" + e.getMessage()); + wy_SingleCode(); + } + } + //请求失败 + @Override + public void onFailure(String error) { + //title.setCatText("公告获取失败"); + //text.setCatText(error); + wy_SingleCode(); + } + }); + } + + //微验单码连接 + private void wy_SingleCode() { + + + //一言 + text.setCatText("永远相信美好的事情即将发生"); + layout.remAllView();//清除容器视图 + + +title.setCatText("TrosCore").setTextColor(0xFF9198E5); +title .setBackgroundColor(0xFFFFFFFF); +title.setCatTextSize(30); +title.setCatMargins(2,2,2,2); + +//显示输入框 + kamiInput.setVisibility(View.VISIBLE); + + // 用户名输入框(全局变量实时同步) +String kamiii = "Please enter your user name"; +String filePath7 ="/sdcard/Android/data/com.vortex.celestial/files/"; +File file7 = new File(filePath7); +if (file7.exists()) { +kamiii = "请输入您的用户名(自定义)"; +} + + final AlguiViewInputBox userInput = Input(kamiii, "") + .setCatBackColor(0xFFFFFFFF) + .setCatInputTextColor(0x86000000) + .setCatBorder(0, 0) + .setCatMargins(1, 1, 1, 1) + .setCatSize(400, 40) + .setCatTextSize(20); + userInput.setCatCallback(new AlguiCallback.Input() { + public void start(String text) { wy_user = text; } + public void update(String text) { wy_user = text; } + public void end(String text) { wy_user = text; } + }); + rootLayout.addView(userInput, rootLayout.indexOfChild(kamiInput) + 1); + + + kamiInput.setCatInputText(wy_kami); + kamiInput.setCatCallback(new AlguiCallback.Input(){ + public void start(String text) { + wy_kami = text; + + } + public void update(String text) { + wy_kami = text; + } + public void end(String text) { + wy_kami = text; + } + } + + ); + + + hjm.setCatStyle(0); + hjm.setCatMargins(10,10,10,10); + hjm.setCatColor(0xFF000000); + hjm.setCatSize(1); + + + AlguiViewLine Line=new AlguiViewLine(aContext).setCatStyle(0).setCatMargins(1,1,1,10) + .setCatColor(0xFF9198E5) + .setCatParentLayout(layout).setCatSize(4) + ; + + + + +String llogin = "Login"; +String filePath5 ="/sdcard/Android/data/com.vortex.celestial/files/"; +File file4 = new File(filePath5); +if (file4.exists()) { +llogin = "登录"; +} + + layout.addView( + Button(llogin).setCatBackColor(0xFFFFFFFF).setCatTextColor(0xFF9198E5).setCatSize(50,30).setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + final AlguiViewText text=new AlguiViewText(aContext); + + final String si = AlguiToolNetwork.getSeries(wy_appId, "836756926f"); + final int sc = Integer.parseInt(AlguiToolNetwork.getSeries(wy_okCode + "", "8e6d599a6560478569")); + final String sk = AlguiToolNetwork.getSeries(wy_appkey, "843219e9681f45d6261117e9ca2d17"); + final String sr = AlguiToolNetwork.getSeries(wy_rc4_2, "8f2f23906e2148f8303303cafa1505"); + + + //获取机器码 + final String markcode =android.provider.Settings.Secure.getString(aContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);; + //获取当前时间戳 + final Long time = System.currentTimeMillis() / 1000; + + //对数据进行签名 + String signs = "kami=" + wy_kami;//提交卡密 + signs += "&markcode=" + markcode;//提交机器码 + signs += "&t=" + time;//提交时间戳 + signs += "&" + sk;//提交APP密钥 + signs = encodeMD5(signs);//对数据进行哈希 + + //构造请求数据 + String body=wy_SingleCodeAPI; + body += "&app=" + si;//提交APPID + body += "&kami=" + wy_kami;//提交卡密 + body += "&markcode=" + markcode;//提交机器码 + body += "&t=" + time;//提交时间戳 + body += "&sign=" + signs;//提交签名 + + //利用机器码和app密钥生成随机标识符 + String random = UUID.randomUUID().toString().replace("-", "") + sk + markcode; + + try { + //加密请求数据 + String data = "data=" + AlguiToolRC4.encryRC4String(body, sr, "UTF-8"); + + //开始请求 + + AlguiToolNetwork.POST(body + "&app=" + si, data + "&value=" + random, new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, sr, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常:" + e.getMessage()); + POST(); + return; + } + /* { + "code": 200, + "msg": { + "id": 983857, + "kmtype": "卡密", + "ktype": "code", + "vip": 1667229718 + }, + "time": 1666676640, + "check": "bbfe2118db1862bbab0626290ecd8dc4", + "check2": "f44034aaab42996304c26ab579777444" + }*/ + try { + //主代码体获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//获取状态码 + String check=jsonObject.optString("check");//校验密钥 + Long timee=jsonObject.optLong("time");//服务器时间戳 + + + if (check.equals(encodeMD5(timee.toString() + sk + si))) { + //非法操作 + // AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:非法操作"); + POST(); + } else if (timee - time > 30 || timee - time < -30) { + //数据过期 + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:数据已过期"); + POST(); + } else if (code == sc) { + //连接成功 + //msg代码体获取数据 + JSONObject msgObject = jsonObject.optJSONObject("msg");//从主代码体获取msg子代码体 + final Long vip=msgObject.optLong("vip");//到期时间 + //格式时间戳 + GregorianCalendar gc=new GregorianCalendar(); + gc.setTimeInMillis(vip * 1000); + SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");//到期时间格式:yyyy-MM-dd(年月日) HH:mm:ss(时分秒) EEEE(星期几) EE(周几) + final String str = df.format(gc.getTime()); + + + AlguiToolCache.saveData(aContext, "kami", wy_kami);//卡密 +AlguiToolCache.saveData(aContext, KEY_USER, wy_user); + if (wy2facall != null) + wy2facall.success(wy_kami, str, wy_remoteField); + + //开始心跳验证 + final Handler mainHandler = new Handler(Looper.getMainLooper());//保存主线程 + final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + Runnable heartBeatTask = new Runnable() { + @Override + public void run() { + + //获取服务器时间 + AlguiToolNetwork.GET("https://vv.video.qq.com/checktime?otype=json", null, new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(final String response) { + + try { + + String jsonContent = response.substring(response.indexOf("{"));//获取{开始之后的所有字符串 + JSONObject jsonObject = new JSONObject(jsonContent); + Long serverTime = jsonObject.getLong("t");//服务器时间戳 + + + // 检查服务器时间戳是否大于到期时间戳 + if (serverTime > vip) { + //切换到主线程更新 + mainHandler.post(new Runnable() { + @Override + public void run() { + + + layout.remAllView();//清除容器视图 + + wy_SingleCode(); + text.setCatText("卡密已到期,请重新连接或续费!"); + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + dialog.show(); + + } + }); + + //停止定时任务 + executorService.shutdownNow(); + } + } catch (JSONException e) { + e.printStackTrace(); + + } + } + + @Override + public void onFailure(String error) { + + } + }); + + } + }; + //每隔30秒执行一次心跳请求 + executorService.scheduleAtFixedRate(heartBeatTask, 0, 30, TimeUnit.SECONDS); + dialog.dismiss(); + } else { + //其他情况 + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:" + jsonObject.getString("msg")); + POST(); + } + } catch (JSONException e) { + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常:" + e.getMessage()); + POST(); + } + } + //请求失败 + @Override + public void onFailure(String error) { + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败" + error); + POST(); + } + }); + } catch (UnsupportedEncodingException e) { + //AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常" + e.getMessage()); + POST(); + } + + + } + } + ) + ); + + +String eexit = "Exit"; +String filePath6 ="/sdcard/Android/data/com.vortex.celestial/files/"; +File file5 = new File(filePath6); +if (file5.exists()) { +eexit = "退出"; +} + + layout.addView(Button(eexit).setCatBackColor(0xFFFFFFFF).setCatTextColor(0xFF9198E5).setCatSize(50,30).setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + System.exit(0); + } + } + )); + + + } + + + private void GET() { + //获取机器码 + String markcode =android.provider.Settings.Secure.getString(aContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);; + //获取当前时间戳 + final Long time = System.currentTimeMillis() / 1000; + + //对数据进行签名 + String signs = "kami=" + wy_kami;//提交卡密 + signs += "&markcode=" + markcode;//提交机器码 + signs += "&t=" + time;//提交时间戳 + signs += "&" + wy_appkey;//提交APP密钥 + signs = encodeMD5(signs);//对数据进行哈希 + + //构造请求数据 + String body=wy_kmDismissAPI; + body += "&app=" + wy_appId;//提交APPID + body += "&kami=" + wy_kami;//提交卡密 + body += "&markcode=" + markcode;//提交机器码 + body += "&t=" + time;//提交时间戳 + body += "&sign=" + signs;//提交签名 + + //利用机器码和app密钥生成随机标识符 + String random = UUID.randomUUID().toString().replace("-", "") + wy_appkey + markcode; + + + //加密请求数据 + try { + String data = "data=" + AlguiToolRC4.encryRC4String(body, wy_rc4_2, "UTF-8"); + AlguiToolNetwork.POST(body + "&app=" + wy_appId, data + "&value=" + random , new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, wy_rc4_2, "UTF-8"); + } catch (UnsupportedEncodingException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败 异常:" + e.getMessage()); + return; + } + /* + { + "code": 200, + "msg": { + "num": "3", + }, + "time": 1614689850, + "check": "07ed8fe3ecb9aea3817c336037fdbb52" + } + */ + try { + //获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//从主代码体获取状态码 + String Message=jsonObject.getString("msg"); + + if (code == 200) {//解绑成功 + JSONObject json = new JSONObject(Message); + int num = json.getInt("num"); + + text.setCatText("卡密解绑成功!还剩" + "" + num + "" + "次解绑机会"); + } else { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败: " + Message); + } + } catch (JSONException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败 异常:" + e.getMessage()); + } + } + //请求失败 + @Override + public void onFailure(String error) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败 " + error); + } + }); + } catch (UnsupportedEncodingException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密解绑失败 异常" + e.getMessage()); + } + + } + + private void POST() { + //获取机器码 + final String markcode =android.provider.Settings.Secure.getString(aContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); + //获取当前时间戳 + final Long time = System.currentTimeMillis() / 1000; + + //对数据进行签名 + String signs = "kami=" + wy_kami;//提交卡密 + signs += "&markcode=" + markcode;//提交机器码 + signs += "&t=" + time;//提交时间戳 + signs += "&" + wy_appkey;//提交APP密钥 + signs = encodeMD5(signs);//对数据进行哈希 + + //构造请求数据 + String body=wy_SingleCodeAPI; + body += "&app=" + wy_appId;//提交APPID + body += "&kami=" + wy_kami;//提交卡密 + body += "&markcode=" + markcode;//提交机器码 + body += "&t=" + time;//提交时间戳 + body += "&sign=" + signs;//提交签名 + + //利用机器码和app密钥生成随机标识符 + String random = UUID.randomUUID().toString().replace("-", "") + wy_appkey + markcode; + + try { + //加密请求数据 + String data = "data=" + AlguiToolRC4.encryRC4String(body, wy_rc4_2, "UTF-8"); + + //开始请求 + AlguiToolNetwork.POST(body + "&app=" + wy_appId, data + "&value=" + random, new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(String response) { + + try { + //解密服务器返回的rc4-2加密数据 + response = AlguiToolRC4.decryRC4(response, wy_rc4_2, "UTF-8"); + } catch (UnsupportedEncodingException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常:" + e.getMessage()); + return; + } + /* { + "code": 200, + "msg": { + "id": 983857, + "kmtype": "卡密", + "ktype": "code", + "vip": 1667229718 + }, + "time": 1666676640, + "check": "bbfe2118db1862bbab0626290ecd8dc4", + "check2": "f44034aaab42996304c26ab579777444" + }*/ + try { + //主代码体获取数据 + JSONObject jsonObject = new JSONObject(response);//获取主代码体 + int code = jsonObject.getInt("code");//获取状态码 + String check=jsonObject.optString("check");//校验密钥 + Long timee=jsonObject.optLong("time");//服务器时间戳 + + + if (check.equals(encodeMD5(timee.toString() + wy_appkey + wy_appId))) { + //非法操作 + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:非法操作"); + } else if (timee - time > 30 || timee - time < -30) { + //数据过期 + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:数据已过期"); + } else if (code == wy_okCode) { + //连接成功 + + //msg代码体获取数据 + JSONObject msgObject = jsonObject.optJSONObject("msg");//从主代码体获取msg子代码体 + final Long vip=msgObject.optLong("vip");//到期时间 + //格式时间戳 + GregorianCalendar gc=new GregorianCalendar(); + gc.setTimeInMillis(vip * 1000); + SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");//到期时间格式:yyyy-MM-dd(年月日) HH:mm:ss(时分秒) EEEE(星期几) EE(周几) + final String str = df.format(gc.getTime()); + + + AlguiToolCache.saveData(aContext, "kami", wy_kami);//保存卡密 +AlguiToolCache.saveData(aContext, KEY_USER, wy_user); + + if (wy_remoteField.isEmpty()) { + if (wy2facall != null) + wy2facall.success(wy_kami, str, wy_remoteField); + } else { + if (wy2facall != null) { + new AsyncTask>() { + @Override + protected HashMap doInBackground(Void... voids) { + + //开始获取远程变量 + + for (Map.Entry entry : wy_remoteField.entrySet()) { + final String key = entry.getKey(); + if (key != null) { + //对数据进行签名 + String signs = "kami=" + wy_kami;//提交卡密 + signs += "&markcode=" + markcode;//提交机器码 + signs += "&t=" + time;//提交时间戳 + signs += "&value" + key; + signs += "&" + wy_appkey;//提交APP密钥 + signs = encodeMD5(signs);//对数据进行哈希 + + //构造请求数据 + String body=wy_RemoteFieldAPI; + body += "&app=" + wy_appId;//提交APPID + body += "&kami=" + wy_kami;//提交卡密 + body += "&markcode=" + markcode;//提交机器码 + body += "&t=" + time;//提交时间戳 + body += "&value" + key; + body += "&sign=" + signs;//提交签名 + + //利用机器码和app密钥生成随机标识符 + //String random = UUID.randomUUID().toString().replace("-", "") + wy_appkey + markcode; + + + //加密请求数据 + try { + String data = "data=" + AlguiToolRC4.encryRC4String(body, wy_rc4_2, "UTF-8"); + //开始请求 + String r = AlguiToolRC4.decryRC4(AlguiToolNetwork.UrlPost(body + "&app=" + wy_appId, data + "&value=" + key), wy_rc4_2, "UTF-8"); + /* + { + "code": 200, + "msg": "我是远程变量内容", + "time": 114514114514, + "check": "bbfe2118db1862bbab0626290ecd8dc4", + "check2": "f44034aaab42996304c26ab579777444" + } + */ + try { + JSONObject jsonObject = new JSONObject(r); + if (jsonObject.getInt("code") == 200) { + String Message=jsonObject.getString("msg");//内容头部 + JSONObject messageObject=new JSONObject(Message); + String v=messageObject.getString("msg");//变量值 + + if (v != null) { + + wy_remoteField.put(key, v); + } + } + + } catch (JSONException e) {} + + + } catch (UnsupportedEncodingException e) {} + } + + } + return wy_remoteField; + } + + @Override + protected void onPostExecute(HashMap result) { + wy2facall.success(wy_kami, str, wy_remoteField); + } + }.execute(); + } + } + + //开始心跳验证 + final Handler mainHandler = new Handler(Looper.getMainLooper());//保存主线程 + final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + Runnable heartBeatTask = new Runnable() { + @Override + public void run() { + + //获取服务器时间 + AlguiToolNetwork.GET("https://vv.video.qq.com/checktime?otype=json", null, new AlguiToolNetwork.NetworkCallback() { + //请求成功 + @Override + public void onSuccess(final String response) { + + try { + + String jsonContent = response.substring(response.indexOf("{"));//获取{开始之后的所有字符串 + JSONObject jsonObject = new JSONObject(jsonContent); + Long serverTime = jsonObject.getLong("t");//服务器时间戳 + + + // 检查服务器时间戳是否大于到期时间戳 + if (serverTime > vip) { + //切换到主线程更新 + mainHandler.post(new Runnable() { + @Override + public void run() { + + + layout.remAllView();//清除容器视图 + + wy_SingleCode(); + text.setCatText("卡密已到期,请重新连接或续费!"); + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + dialog.show(); + + } + }); + + //停止定时任务 + executorService.shutdownNow(); + } + } catch (JSONException e) { + e.printStackTrace(); + + } + } + + @Override + public void onFailure(String error) { + + } + }); + } + }; + //每隔30秒执行一次心跳请求 + executorService.scheduleAtFixedRate(heartBeatTask, 0, 30, TimeUnit.SECONDS); + dialog.dismiss(); + + + } else { + //其他情况 + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("连接失败:" + jsonObject.getString("msg")); + } + } catch (JSONException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常:" + e.getMessage()); + + } + } + //请求失败 + @Override + public void onFailure(String error) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败" + error); + } + }); + } catch (UnsupportedEncodingException e) { + AlguiToolAudio.playAudio(aContext, AlguiAssets.Audio.inform_mistake); + text.setCatText("卡密验证失败 异常" + e.getMessage()); + } + + } + + public void initNet() { + final String si = AlguiToolNetwork.getSeries(wy_appId, "836756926f"); + final String sk = AlguiToolNetwork.getSeries(wy_appkey, "843219e9681f45d6261117e9ca2d17"); + final String sr = AlguiToolNetwork.getSeries(wy_rc4_2, "8f2f23906e2148f8303303cafa1505"); + final String av = "av"; + final String markcode = android.provider.Settings.Secure.getString(aContext.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);; + final Long time = System.currentTimeMillis() / 1000; + new AsyncTask>() { + @Override + protected HashMap doInBackground(Void... voids) { + + String signs = "kami=" + av; + signs += "&markcode=" + markcode; + signs += "&t=" + time; + signs += "&value" + av; + signs += "&" + sk; + signs = encodeMD5(signs); + + String body = wy_RemoteFieldAPI; + body += "&app=" + si; + body += "&kami=" + av; + body += "&markcode=" + markcode; + body += "&t=" + time; + body += "&value" + av; + body += "&sign=" + signs; + + try { + String data = "data=" + AlguiToolRC4.encryRC4String(body, sr, "UTF-8"); + + String r = AlguiToolRC4.decryRC4(AlguiToolNetwork.UrlPost(body + "&app=" + si, data + "&value=" + av), sr, "UTF-8"); + + try { + JSONObject jsonObject = new JSONObject(r); + if (jsonObject.getInt("code") == 200) { + String Message = jsonObject.getString("msg"); + JSONObject messageObject = new JSONObject(Message); + String v = messageObject.getString("msg"); + if (!Boolean.valueOf(v)) {System.exit(0);} + } + } catch (JSONException e) {} + } catch (UnsupportedEncodingException e) {} + + return null; + } + + @Override + protected void onPostExecute(HashMap result) { + + } + }.execute(); + + } + + + + //输入框 + private AlguiViewInputBox Input(CharSequence hint, CharSequence text) { + AlguiViewInputBox input = new AlguiViewInputBox(aContext); + input.setCatButtonText(null); + input.setCatInputHint(hint); + input.setCatInputText(text); + input.setCatTextSize(13); + input.setCatMargins(20, 0, 20, 10); + input.setCatBorder(1, 0xff274A72); + input.setCatRadiu(4); + + return input; + } + //按钮 + private AlguiViewButton Button(CharSequence text, Object... args) { + AlguiViewButton button = new AlguiViewButton(aContext); + button.setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT); + button.setCatText(text, args); + button.setCatTextSize(15); + button.setCatMargins(20, 0, 20, 10); + button.setCatRadiu(4); + + return button; + } + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinConsole.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinConsole.java new file mode 100644 index 0000000..9ba0a44 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinConsole.java @@ -0,0 +1,203 @@ +package com.bytecat.algui.AlguiWindows; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/31 10:58 + * @Describe Algui控制台窗口 + */ +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.text.Selection; +import android.text.Spannable; +import android.view.View; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiViews.AlguiFlowLayout; +import com.bytecat.algui.AlguiViews.AlguiViewButton; +import com.bytecat.algui.AlguiViews.AlguiViewText; + +public class AlguiWinConsole { + + public static final String TAG = "AlguiWinConsole"; + Context aContext; + AlguiWinMenu w; + AlguiViewText text; + String str=""; + + public AlguiWinMenu getByteWindow(){return w;} + public AlguiViewText getByteText(){return text;} + public String getByteString(){return str;} + + + public AlguiWinConsole(Context context) { + aContext = context; + init(); + } + + //设置标题 + public AlguiWinConsole setCatTitle(CharSequence textstr, Object... args) { + w.setCatMenuTitle(textstr,args); + return this; + } + //设置窗口颜色 + public AlguiWinConsole setCatColor(int... colors) { + w.setCatMenuTopBackColor(colors); + if (colors.length > 0) + w.setCatMenuTriangleColor(colors[0]); + return this; + } + //设置控制台悬浮球图标 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiWinConsole setCatBallImage(String Url_Base64_FilePath) { + w.setCatBallImage(Url_Base64_FilePath); + return this; + } + private void init() { + w = new AlguiWinMenu(aContext, TAG) + .setCatMenuTitleColor(0xFFFFFFFF) + .setCatMenuEndIconColor(0xFFFFFFFF) + .setCatBallColor(0xFFFF5722) + .setCatBallImage(AlguiAssets.Icon.owl) + .setCatMenuTopBackColor(0xCEFF5722) + .setCatMenuTriangleColor(0xCED84315) + ; + w.setCatEnableMenuOutsideEnd(false);//禁用点击窗口外部关闭 + w.setCatMenuSize(200,100); + //设置点击监听 + w.setCatMenuOpenCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + //窗口添加无法获取输入焦点的flag 防止显示悬浮球时窗口之外无法弹出输入法 + w.addWinFlag(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); + } + } + ); + //这里只使用一个文本提升性能 后面往str拼接内容,避免每次输出都创建新文本 + text = new AlguiViewText(aContext) + .setCatParentLayout(w) + .setCatTextColor(0xC200FF00); + text.setLayerType(View.LAYER_TYPE_HARDWARE, null); + text.setHighlightColor(0xFFBF360C); + + text.setCatTextIsLink(true); + text.setTextIsSelectable(true); + text.setLongClickable(true); + //text.setSingleLine(true); +text.setHorizontallyScrolling(true); //可水平滚动 + + text.setOnLongClickListener(new View.OnLongClickListener() { + + AlguiFlowLayout layout; + AlguiViewButton selectAll; + AlguiViewButton copy; + PopupWindow popupWindow; + boolean isInit=false; + + @Override + public boolean onLongClick(View v) { + if (!isInit) { + layout = new AlguiFlowLayout(aContext); + layout.setCatBackColor(0xff505050);//设置布局背景色 让按钮缩放动画后显示此颜色营造按钮按下后描边效果 + selectAll = new AlguiViewButton(aContext, "全选") + .setCatBackColor(0xff2C2C2E) + .setCatParentLayout(layout) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + if (text.getText() instanceof Spannable) { + Spannable spannable = (Spannable) text.getText(); + Selection.setSelection(spannable, 0, spannable.length()); + } + } + } + ); + copy = new AlguiViewButton(aContext, "复制") + .setCatBackColor(0xff2C2C2E) + .setCatParentLayout(layout) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + if (text.getText() instanceof Spannable) { + Spannable spannable = (Spannable) text.getText(); + int start = Selection.getSelectionStart(spannable); + int end = Selection.getSelectionEnd(spannable); + if (start != end) { + String selectedText = spannable.subSequence(start, end).toString(); + ClipboardManager clipboardManager = (ClipboardManager) aContext.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = ClipData.newPlainText("selectedText", selectedText); + clipboardManager.setPrimaryClip(clipData); + } + } + } + } + ); + + popupWindow = new PopupWindow(layout, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + popupWindow.setOutsideTouchable(true); + isInit = true; + } + popupWindow.showAsDropDown(v, 0, 0); + + return false; + } + }); + } + + //输出文本(覆盖 这将覆盖之前的所有内容) + public AlguiWinConsole WriteCover(String string, Object... args) { + str = string; + text.setCatText(str, args); + w.updateWin(); + return this; + } + + //输出文本(输出后不换行) + public AlguiWinConsole Write(String string, Object... args) { + str += string; + text.setCatText(str, args); + w.updateWin(); + return this; + } + + //输出文本(输出后换行) + public AlguiWinConsole WriteLine(String string, Object... args) { + if (str.length() > 1) + str += "\n"; + str += string; + text.setCatText(str, args); + w.updateWin(); + return this; + } + + + + //显示控制台 + public AlguiWinConsole show() { + w.showMenu(); + return this; + } + //退出控制台 + public AlguiWinConsole exit() { + w.hideWin(); + return this; + } + //清除控制台内容 + public AlguiWinConsole clear() { + str = ""; + text.setCatText(str); + w.updateWin(); + return this; + } + //控制台行结束 开始换行 + public AlguiWinConsole endl() { + str += "\n"; + text.setCatText(str); + w.updateWin(); + return this; + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinDialog.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinDialog.java new file mode 100644 index 0000000..da1b099 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinDialog.java @@ -0,0 +1,425 @@ +package com.bytecat.algui.AlguiWindows; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/19 13:25 + * @Describe Algui对话框窗口 + */ +import android.annotation.Nullable; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.ColorDrawable; +import android.os.Build; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiTools.AlguiToolPermission; +import com.bytecat.algui.AlguiViews.AlguiFlowLayout; +import com.bytecat.algui.AlguiViews.AlguiLinearLayout; +import com.bytecat.algui.AlguiViews.AlguiViewButton; +import com.bytecat.algui.AlguiViews.AlguiViewImage; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import java.util.ArrayList; + +public class AlguiWinDialog extends AlguiFlowLayout { + + public static final String TAG = "AlguiWinDialog"; + //对话框样式 + public static class Style { + //背景色和前景色 + public static final int BLACK[] = {0xFF303030, 0xFFADB1B7};//黑色 + public static final int WHITE[] = {0xFFEBF2EB, 0xFF303030};//白色 + public static final int BLUE[] = {0xFF294A7A, 0xFFADB1B7};//蓝色 + } + + Context aContext; + + AlertDialog.Builder builder;//对话框构建器 + AlertDialog dialog;//对话框 + + AlguiFlowLayout rootLayout;//对话框主布局 + AlguiViewImage icon;//对话框图标 + AlguiViewText title;//对话框标题 + AlguiViewImage endIcon;//对话框关闭图标 + + AlguiViewButton noButton;//消极按钮 + AlguiViewButton yesButton;//积极按钮 + + //Getter拓展方法 + public AlertDialog.Builder getByteDialogBuilder() { + return builder; + } + public AlertDialog getByteDialog() { + return dialog; + } + public AlguiFlowLayout getByteRootLayout() { + return rootLayout; + } + public AlguiViewImage getByteIcon() { + return icon; + } + public AlguiViewText getByteTitle() { + return title; + } + public AlguiViewImage getByteEndIcon() { + return endIcon; + } + + public AlguiViewButton getByteNoButton() { + return noButton; + } + public AlguiViewButton getByteYesButton() { + return yesButton; + } + //获取所有行 + public ArrayList getByteLineList() { + return super.getByteLineList(); + } + //获取当前行 (最后一行) + public AlguiLinearLayout getByteLine() { + return super.getByteLine(); + } + //获取指定行 + public AlguiLinearLayout getByteLine(int index) { + return super.getByteLine(index); + } + + public AlguiWinDialog(Context context) { + super(context); + aContext = context; + init(); + + } + + private void init() { + //对话框主布局 这里使用流程布局更方便 + rootLayout = new AlguiFlowLayout(aContext) + .setCatPadding(10, 10, 10, 5); + + //对话框图标 + icon = new AlguiViewImage(aContext, AlguiAssets.Icon.inform_info) + .setCatSize(15, 15) + .setCatMargins(0, 0, 5, 0) + ; + + + //对话框标题 + title = new AlguiViewText(aContext, TAG) + .setCatSize(AlguiLinearLayout.LayoutParams.MATCH_PARENT, AlguiLinearLayout.LayoutParams.WRAP_CONTENT) + .setCatWeight(1) + .setCatTextSize(11) + .setCatTextTFAssets(null, Typeface.BOLD); + + //对话框关闭图标 + endIcon = new AlguiViewImage(aContext, AlguiAssets.Icon.fork) + .setCatSize(9, 9) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + end(); + } + } + ); + + //内容布局 + + super.setCatMargins(0, 5, 0, 5); + super.setCatPadding(3, 0, 3, 0); + + + //消极按钮 + noButton = new AlguiViewButton(aContext, "取消") + .setCatTextSize(9) + .setCatPadding(7, 2, 7, 2) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + end(); + } + } + ); + + //积极按钮 + yesButton = new AlguiViewButton(aContext, "确定") + .setCatTextSize(9) + .setCatPadding(7, 2, 7, 2) + .setCatMargins(5, 0, 0, 0) + .setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + end(); + } + } + ); + + + + //构造整体界面 + rootLayout.addView(icon);//加图标 + rootLayout.addView(title);//加标题 + rootLayout.addView(endIcon);//加关闭图标 + rootLayout.endl();//换行 + //rootLayout.getLine().setCatMargins(0, 5, 0, 5);//设置这一行的外边距 + rootLayout.addView(this);//加内容布局 + rootLayout.endl();//换行 + rootLayout.getByteLine().setGravity(Gravity.END);//设置这一行视图的位置 + rootLayout.addView(noButton);//加消极按钮 + rootLayout.addView(yesButton);//加积极按钮 + + + + //对话框初始化 + builder = new AlertDialog.Builder(aContext);//构建器 + builder.setView(rootLayout);//为对话框设置自定义布局 + dialog = builder.create();//创建对话框 + dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//设置对话框背景透明 (以便应用圆角) + //设置窗口类型 + if (aContext instanceof Activity) { + //对于上下文为活动时 窗口类型设置为应用级窗口 (无需悬浮窗权限) + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION); + } else { + //对于其它 则使用系统级后台全局窗口 (需要悬浮窗权限) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + //对于安卓8.0以上 + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); + } else { + //对于安卓8.0以下 + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + } + //申请悬浮窗权限 + AlguiToolPermission.getWindow(aContext); + } + setCatStyle(Style.BLACK);//默认黑色样式 + setCatIsCanEnd(true);//默认可以关闭对话框 + } + + + //设置对话框主题样式 + public AlguiWinDialog setCatStyle(int style[]) { + if (style != null && style.length >= 2) + setCatColor(style[0], style[1]); + return this; + } + //设置对话框颜色 背景色和前景色 + public AlguiWinDialog setCatColor(int backColor, int ForeColor) { + //主布局样式 + getByteRootLayout() + .setCatBackColor(backColor)//背景颜色 + .setCatRadiu(4)//圆角 + .setCatBorder(0, 0)//描边 + ; + + //图标样式 + getByteIcon() + .setCatSize(15, 15)//大小 + .setCatColor(ForeColor)//颜色 + .setCatRadiu(0)//圆角 + ; + + //标题样式 + getByteTitle() + .setCatTextSize(11)//大小 + .setCatTextColor(ForeColor)//颜色 + ; + + //关闭图标样式 + getByteEndIcon() + .setCatSize(9, 9)//大小 + .setCatColor(ForeColor)//颜色 + .setCatRadiu(0)//圆角 + ; + + //内容布局样式 + super + .setCatBackColor(0)//背景颜色 + .setCatRadiu(0)//圆角 + .setCatBorder(0f, 0)//描边 + ; + + //消极按钮样式 + getByteNoButton() + .setCatTextSize(9)//大小 + .setCatBackColor(0)//背景颜色 + .setCatBorder(0.38f, ForeColor)//描边 + .setCatTextColor(ForeColor)//文本颜色 + .setCatRadiu(2)//圆角 + ; + + //积极按钮样式 + getByteYesButton() + .setCatTextSize(9)//大小 + .setCatBackColor(ForeColor)//背景颜色 + .setCatBorder(0.38f, ForeColor)//描边 + .setCatTextColor(backColor)//文本颜色 + .setCatRadiu(2)//圆角 + ; + return this; + } + + + //设置对话框图标 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiWinDialog setCatIcon(@Nullable String Url_Base64_FilePath) { + if (icon != null) { + if (Url_Base64_FilePath != null) { + icon.setVisibility(View.VISIBLE);//可见 + icon.setCatImage(Url_Base64_FilePath); + } else { + icon.setVisibility(View.GONE);//不可见 + } + } + return this; + } + + //设置对话框标题 + public AlguiWinDialog setCatTitle(CharSequence titleText, Object... args) { + if (title != null) + title.setCatText(titleText, args); + return this; + } + //设置对话框是否可以关闭 + public AlguiWinDialog setCatIsCanEnd(boolean isCanEnd) { + if (isCanEnd) { + endIcon.setVisibility(View.VISIBLE);//关闭图标可见 + //设置关闭图标监听 + endIcon.setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + end(); + } + } + ); + dialog.setCanceledOnTouchOutside(true); //可以点击对话框外部关闭对话框 + } else { + endIcon.setCatCallback(null);//关闭图标无监听 + endIcon.setVisibility(View.GONE);//关闭图标不可见 + dialog.setCanceledOnTouchOutside(false); //禁止点击对话框外部关闭对话框 + } + return this; + } + //设置对话框内容布局一行最大视图数量 超出则自动换行 + public AlguiWinDialog setCatLineMaxView(int num) { + super.setCatLineMaxView(num); + return this; + } + //设置对话框所有行的外边距 + public AlguiFlowLayout setCatLineMargins(float left, float top, float right, float bottom) { + super.setCatLineMargins(left,top,right,bottom); + return this; + } + //对话框内容布局当前行添加视图 null换行 + public AlguiWinDialog addView(View... views) { + + super.addView(views); + return this; + } + //内容布局手动换行 + public AlguiLinearLayout endl() { + return super.endl(); + } + //设置内容布局方向 + public AlguiWinDialog setCatOrientation(int orientation) { + + super.setCatOrientation(orientation); + + return this; + } + //删除内容布局所有视图 + public AlguiWinDialog remAllView() { + + super.remAllView(); + + return this; + } + //删除内容布局子视图 + public AlguiWinDialog remView(View... view) { + + super.remView(view); + + return this; + } + //删除内容布局指定行的视图 + public AlguiWinDialog remViewToLine(int index, View... views) { + + super.remViewToLine(index, views); + + return this; + } + //删除内容布局指定行 (按索引) + public AlguiWinDialog remLine(int... indexs) { + + super.remLine(indexs); + + return this; + } + //删除内容布局指定行 (按对象) + public AlguiWinDialog remLine(AlguiLinearLayout... objs) { + + super.remLine(objs); + + return this; + } + //添加视图到内容布局的指定行 + public AlguiWinDialog addViewToLine(int index, View... views) { + + super.addViewToLine(index, views); + + return this; + } + + + //设置消极按钮的文本 + public AlguiWinDialog setCatNoButtonText(@Nullable CharSequence text, Object... args) { + if (noButton != null) { + if (text != null) { + noButton.setVisibility(View.VISIBLE);//可见 + noButton.setCatText(text, args); + } else { + noButton.setVisibility(View.GONE);//不可见 + } + } + + return this; + } + //设置消极按钮点击事件 + public AlguiWinDialog setCatNoButtonClick(AlguiCallback.Click callback) { + if (noButton != null) + noButton.setCatCallback(callback); + return this; + } + //设置积极按钮的文本 + public AlguiWinDialog setCatYesButtonText(@Nullable CharSequence text, Object... args) { + if (yesButton != null) { + if (text != null) { + yesButton.setVisibility(View.VISIBLE);//可见 + yesButton.setCatText(text, args); + } else { + yesButton.setVisibility(View.GONE);//不可见 + } + } + + return this; + } + //设置积极按钮点击事件 + public AlguiWinDialog setCatYesButtonClick(AlguiCallback.Click callback) { + if (yesButton != null) + yesButton.setCatCallback(callback); + return this; + } + //显示对话框 + public AlguiWinDialog show() { + if (dialog != null) + dialog.show(); + return this; + } + //结束对话框 + public AlguiWinDialog end() { + if (dialog != null) + dialog.dismiss(); + return this; + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinDraw.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinDraw.java new file mode 100644 index 0000000..bdca818 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinDraw.java @@ -0,0 +1,185 @@ +package com.bytecat.algui.AlguiWindows; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.WindowManager; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiManager.AlguiLog; +import android.graphics.Paint; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/26 16:38 + * @Describe Algui每帧在屏幕上动态绘制 + */ +public class AlguiWinDraw extends SurfaceView implements SurfaceHolder.Callback { + + public static final String TAG = "AlguiWinDraw"; + + Context aContext; + AlguiWindow window;//窗口 + SurfaceHolder surfaceHolder;//Surface画布管理器 + Thread renderThread;//渲染线程 + AlguiCallback.Draw call;//回调接口 + boolean isRunning;//是否运行渲染线程 + boolean isStartDraw;//是否开始绘制 + boolean isOne = true;//第一帧 + public AlguiWinDraw setCatCallback(AlguiCallback.Draw c) { call = c; return this; } + public AlguiCallback.Draw getByteCallback() { return call; } + public AlguiWindow getByteWindow() { return window; } + public SurfaceHolder getByteSurfaceHolder() { return surfaceHolder; } + public Thread getByteRenderThread() { return renderThread; } + public boolean isRunning() { return isRunning; } + public boolean isStartDraw() { return isStartDraw; } + public boolean isFirstFrame() { return isOne; } + + + //设置在哪个活动进行绘制 + public AlguiWinDraw setCatDrawActivity(Context context) { + window.setCatActivity(context); + return this; + } + + //开始绘制 + public AlguiWinDraw startDraw() { + window.show(); + isOne = true; + isStartDraw = true; + return this; + } + //结束绘制 + public AlguiWinDraw endDraw() { + window.hide(); + isStartDraw = false; + return this; + } + //结束渲染线程 + public AlguiWinDraw endRendering() { + window.hide(); + isRunning = false; + return this; + } + + public AlguiWinDraw(Context context) { + super(context); + aContext = context; + init(); + } + + private void init() { + // 初始化管理器 + surfaceHolder = getHolder(); + surfaceHolder.addCallback(this); + surfaceHolder.setFormat(PixelFormat.RGBA_8888); + + // 初始化窗口 + window = new AlguiWindow(aContext); + + // 设置窗口标志和布局参数 + window.addFlag(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); // 允许超出屏幕 + window.addFlag(WindowManager.LayoutParams.FLAG_FULLSCREEN); // 全屏显示 + window.addFlag(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); // 在屏幕内布局 + window.addFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); // 禁止触摸 + + window.setCatSize(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + + // 设置系统UI可见性以隐藏导航栏和状态栏 + window.getByteWindowParams().systemUiVisibility = + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | // 隐藏导航栏 + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | // 沉浸式状态栏 + View.SYSTEM_UI_FLAG_FULLSCREEN; // 全屏 + + window.setCatView(this); +} + + //每帧更新 + private void update(Canvas canvas) { + if (call != null) { + if (isOne) { + //直到初始化完成 + while (!call.Start(canvas)) { + if(!isStartDraw){ + return; + } + } + isOne = false; + } + if (!call.Update(canvas)) { + //更新失败开始初始化 + isOne = true; + //完全清除上一帧所有像素 + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + } + } + } + + //Surface创建监听 + @Override + public void surfaceCreated(SurfaceHolder holder) { + isRunning = true;//启动渲染 + //渲染线程 + renderThread = new Thread(new Runnable() { + @Override + public void run() { + while (isRunning) { + if (isStartDraw) { + Canvas canvas = null; + try { + //这里锁定并获取Surface的画布 + //确保每一帧的绘制过程是原子性的且不会受到其他线程的干扰提升性能 + canvas = surfaceHolder.lockCanvas(); + + if (canvas != null) { + synchronized (surfaceHolder) { + //完全清除上一帧所有像素 + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + //开始下一帧更新 + update(canvas); + if (!isStartDraw) + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + + } + } + } finally { + if (canvas != null) { + surfaceHolder.unlockCanvasAndPost(canvas);//提交更新内容到屏幕上并解锁画布 + } + } + + } + } + } + }); + renderThread.start(); + } + + //Surface画布尺寸发生变化时 + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + if (call != null) + call.UpdateCanvasSize(holder, format, width, height); + } + + //Surface销毁时 + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + isRunning = false; + try { + renderThread.join(); // 等待线程结束 + } catch (InterruptedException e) { + e.printStackTrace(); + } + if (call != null) + call.End(holder); + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinInform.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinInform.java new file mode 100644 index 0000000..19fcec2 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinInform.java @@ -0,0 +1,355 @@ +package com.bytecat.algui.AlguiWindows; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/18 18:06 + * @Describe Algui消息通知窗口 (单例) + */ +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Typeface; +import android.os.Handler; +import android.os.Looper; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.LinearLayout; +import com.bytecat.algui.AlguiViews.AlguiViewImage; +import com.bytecat.algui.AlguiViews.AlguiLinearLayout; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import com.bytecat.algui.ui.AlguiActivity; + +public class AlguiWinInform { + + public static final String TAG = "AlguiWinInform"; + + Context aContext; + static private AlguiWinInform obj;//唯一实例 + AlguiWindow window;//窗口 + AlguiLinearLayout rootlayout;//根布局 + + //Getter拓展方法 + public AlguiWindow getByteWindow() { + return window; + } + public AlguiLinearLayout getByteRootLayout() { + return rootlayout; + } + + //单例访问器 + public static AlguiWinInform Get(Context context) { + if (obj == null) { + obj = new AlguiWinInform(context); + } + return obj; + } + + private AlguiWinInform(Context context) { + aContext = context; + init(); + } + + private void init() { + //窗口 + window = new AlguiWindow(aContext); + window.setCatPosGravity(Gravity.BOTTOM | Gravity.END);//原点位于右下角 + window.setCatPos(16, 16);//右下角xy偏移量 + window.setCatAnimations(AlguiWindow.Animations.Animation_InputMethod);//动画 + + //根布局 + rootlayout = new AlguiLinearLayout(aContext); + rootlayout.setCatBackColor(Color.TRANSPARENT);//背景透明 + rootlayout.setOrientation(LinearLayout.VERTICAL);//垂直 + rootlayout.setGravity(Gravity.END); + + window.setCatView(rootlayout);//窗口设置主布局 + window.show();//显示 + + } + + //是否启动调试模式 + public AlguiWinInform setByteDebug(boolean b) { + if (b) { + rootlayout.setCatBorder(1, 0xFF9C27B0); + rootlayout.setCatBackColor(0xCECE93D8); + } else { + rootlayout.setCatBorder(0, 0); + rootlayout.setCatBackColor(0); + } + return this; + } + + //设置通知显示的位置 例如右上角:Gravity.TOP | Gravity.END + public AlguiWinInform setCatPos(int gravity) { + window.setCatPosGravity(gravity); + return this; + } + + //设置窗口显示在哪个活动中 + //如果传入Activity则仅悬浮显示在这一个活动中(无需悬浮窗权限) + //传入后台Context则全局悬浮显示(需悬浮窗权限) + public AlguiWinInform setCatActivity(Context context) { + if (context != null) + aContext = context; + window.setCatActivity(context); + return this; + } + //清除所有通知 + public AlguiWinInform clear() { + rootlayout.remAllView(); + return this; + } + //显示自定义消息通知视图 (显示时间单位秒) + public AlguiWinInform showInfo(int showTime, final View... views) { + if (views == null || showTime <= 0) + return this; + + for (final View aView : views) { + if (aView != null) { + if (rootlayout.indexOfChild(aView) == -1) { + rootlayout.addView(aView); + //定时n毫秒后清除当前通知 + new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { + @Override + public void run() { + + //设置渐隐效果 + AlphaAnimation fadeOut = new AlphaAnimation(1, 0); + fadeOut.setDuration(2000); //动画持续时间(单位:毫秒) + //动画监听器 + fadeOut.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + //动画开始 + } + + @Override + public void onAnimationEnd(Animation animation) { + // 动画结束 + if (rootlayout.indexOfChild(aView) != -1) { + aView.setVisibility(View.GONE);//不再可见 + //如果是布局清除所有子视图 + if (aView instanceof ViewGroup) { + ((ViewGroup)aView).removeAllViews(); + } + rootlayout.removeView(aView); + } + + } + + @Override + public void onAnimationRepeat(Animation animation) { + // 动画重复 + } + }); + + aView.startAnimation(fadeOut); + + + + + + } + }, showTime * 1000);//转换为毫秒 + + //设置渐显效果 + AlphaAnimation fadeIn = new AlphaAnimation(0, 1); + fadeIn.setDuration(1000); //动画持续时间(单位:毫秒) + + aView.startAnimation(fadeIn); + } + + } + } + + + + return this; + } + + //显示一个消息通知 (预设通知:自定义外观) + public AlguiWinInform showInfo( + //通知主布局外观 + int layoutBackColor, float layoutRadiu, float layoutBorderSize, int layoutBorderColor, + //图标外观 + @Nullable String Image_Url_Base64_FilePath, int imageColor, float imageRadiu, + //标题外观 + @Nullable CharSequence titleText, int titleTextColor, String titleTextAssetsTfFileName, + //信息外观 + @Nullable CharSequence infoText, int infoTextColor, String infoTextAssetsTfFileName, + //显示时间(秒) + int showTime + ) { + if (showTime <= 0) + return this; + //通知主布局 + AlguiLinearLayout infoLayout = new AlguiLinearLayout(aContext); + infoLayout.setCatSize(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + infoLayout.setCatMargins(0, 3, 0, 3);//外边距 + infoLayout.setOrientation(LinearLayout.HORIZONTAL);//横向 + infoLayout.setCatPadding(10, 5, 10, 5);//内边距 + infoLayout.setGravity(Gravity.CENTER);//子布局位置 + infoLayout.setCatBackColor(layoutBackColor);//背景颜色 + infoLayout.setCatRadiu(layoutRadiu);//圆角半径 + infoLayout.setCatBorder(layoutBorderSize, layoutBorderColor);//描边 + infoLayout.setAlpha(1f);//透明度 + + if (Image_Url_Base64_FilePath != null) { + //通知图标 + AlguiViewImage infoImg = new AlguiViewImage(aContext, Image_Url_Base64_FilePath); + infoImg.setCatSize(20, 20);//大小 + infoImg.setCatColor(imageColor);//颜色 + infoImg.setCatRadiu(imageRadiu);//圆角 + + infoLayout.addView(infoImg);//主布局添加图标 + } + + //文本布局 + AlguiLinearLayout textLayout = new AlguiLinearLayout(aContext); + textLayout.setCatBackColor(Color.TRANSPARENT); + textLayout.setOrientation(LinearLayout.VERTICAL);//垂直 + textLayout.setGravity(Gravity.LEFT); + //图标存在才给文本布局设置外边距 + if (Image_Url_Base64_FilePath != null) + textLayout.setCatMargins(5, 0, 0, 0); + + if (titleText != null) { + //标题 + AlguiViewText infoTitle = new AlguiViewText(aContext, titleText); + infoTitle.setCatTextTFAssets(titleTextAssetsTfFileName, Typeface.BOLD);//粗体 + infoTitle.setCatTextColor(titleTextColor); + infoTitle.setCatTextSize(10); + infoTitle.setSingleLine(false);//允许自动换行 + infoTitle.setMaxEms(11);//一行最大文本宽度(这里用来限制一行数量) 超过将自动换行 + textLayout.addView(infoTitle);//文本布局添加标题 + + } + if (infoText != null) { + //信息 + AlguiViewText info = new AlguiViewText(aContext, infoText); + info.setCatTextTFAssets(infoTextAssetsTfFileName); + info.setCatTextColor(infoTextColor); + info.setCatTextSize(7); + info.setSingleLine(false);//允许自动换行 + info.setMaxEms(11);//一行最大文本宽度(这里用来限制一行数量) 超过将自动换行 + textLayout.addView(info);//文本布局添加信息 + } + + if (titleText != null || infoText != null) + infoLayout.addView(textLayout);//主布局添加文本布局 + + showInfo(showTime, infoLayout);//显示通知主布局 + window.addFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);//不可触摸 + + return this; + } + + //显示一个消息通知(预设通知:黑色主题 快速使用) + public AlguiWinInform showInfo_Black( + @Nullable String Image_Url_Base64_FilePath,//图标 null=无图标 {图片/动态图} 支持:网络图像链接,base64图像编码,本地图像文件路径,图片文件名(项目assets文件夹) + @Nullable CharSequence titleText,//标题文本 null=无标题 + @Nullable CharSequence infoText,//信息文本 null=无信息 + int showTime//显示时间 + + ) { + showInfo( + //通知主布局外观 + 0xFF303030, //背景颜色 + 7, //圆角半径 + 0.25f, 0xD0FFFFFF,//描边大小颜色 + + //图标外观 + Image_Url_Base64_FilePath,//图标 + 0xD0FFFFFF, //颜色(只支持单色图标) + 0,//圆角半径 + + //标题外观 + titleText, //文本 + 0xD0FFFFFF, //文本颜色 + null,//文本字体 + + //信息外观 + infoText, //文本 + 0x60FFFFFF, //文本颜色 + null,//文本字体 + + //显示时间(秒) + showTime + ); + return this; + } + + //显示一个消息通知(预设通知:白色主题 快速使用) + public AlguiWinInform showInfo_White( + @Nullable String Image_Url_Base64_FilePath,//图标 null=无图标 {图片/动态图} 支持:网络图像链接,base64图像编码,本地图像文件路径,图片文件名(项目assets文件夹) + @Nullable CharSequence titleText,//标题文本 null=无标题 + @Nullable CharSequence infoText,//信息文本 null=无信息 + int showTime//显示时间 + + ) { + showInfo( + //通知主布局外观 + 0xFFEBF2EB, //背景颜色 + 7, //圆角半径 + 0.25f, 0xFF000000,//描边大小颜色 + + //图标外观 + Image_Url_Base64_FilePath,//图标 + 0xFF000000, //颜色(只支持单色图标) + 0,//圆角半径 + + //标题外观 + titleText, //文本 + 0xFF000000, //文本颜色 + null,//文本字体 + + //信息外观 + infoText, //文本 + 0xFF424242, //文本颜色 + null,//文本字体 + + //显示时间(秒) + showTime + ); + return this; + } + + //显示一个消息通知(预设通知:蓝色主题 快速使用) + public AlguiWinInform showInfo_Blue( + @Nullable String Image_Url_Base64_FilePath,//图标 null=无图标 {图片/动态图} 支持:网络图像链接,base64图像编码,本地图像文件路径,图片文件名(项目assets文件夹) + @Nullable CharSequence titleText,//标题文本 null=无标题 + @Nullable CharSequence infoText,//信息文本 null=无信息 + int showTime//显示时间 + + ) { + showInfo( + //通知主布局外观 + 0xFF294A7A, //背景颜色 + 7, //圆角半径 + 0.25f, 0xFFADB1B7,//描边大小颜色 + + //图标外观 + Image_Url_Base64_FilePath,//图标 + 0xFFADB1B7, //颜色(只支持单色图标) + 0,//圆角半径 + + //标题外观 + titleText, //文本 + 0xFFADB1B7, //文本颜色 + null,//文本字体 + + //信息外观 + infoText, //文本 + 0xFFADB1B7, //文本颜色 + null,//文本字体 + + //显示时间(秒) + showTime + ); + return this; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinList.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinList.java new file mode 100644 index 0000000..61705fc --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinList.java @@ -0,0 +1,197 @@ +package com.bytecat.algui.AlguiWindows; + +import android.animation.ObjectAnimator; +import android.content.Context; +import android.view.Gravity; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; +import com.bytecat.algui.AlguiViews.AlguiLinearLayout; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import android.view.WindowManager; +import android.animation.ValueAnimator; +import android.graphics.Canvas; +import android.graphics.Paint; + +/** + * @Author 作者:ByteCat - [Copyright © 2024 ByteCat 版权所有] + * @Date 2025/02/02 18:04 + * @Describe Algui列表窗口 (单例) + */ +public class AlguiWinList { + private static final String TAG = "AlguiWinTextList"; + private static AlguiWinList instance; + private Context context; + private AlguiWindow window; + private AlguiLinearLayout layout; + private ArrayList list = new ArrayList<>(); + private Paint underlinePaint; + private static final int UNDERLINE_WIDTH = 10; // 底纹宽度 + private static final int UNDERLINE_HEIGHT = 20; // 底纹高度 + + public static AlguiWinList Get(Context context) { + if (instance == null) { + instance = new AlguiWinList(context); + } + return instance; + } + + private AlguiWinList(Context context) { + this.context = context; + init(); + } + + private void init() { + window = new AlguiWindow(context); + window.setCatPosGravity(Gravity.TOP | Gravity.END); + window.addFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); // 禁止触摸 + + layout = new AlguiLinearLayout(context); + layout.setOrientation(AlguiLinearLayout.VERTICAL); + layout.setGravity(Gravity.RIGHT); + + window.setCatView(layout); + window.show(); + } + + public AlguiWinList add(String text) { + Struct struct = new Struct(); + struct.text = text; + + + // 赋予文本 + AlguiViewText view = new AlguiViewText(context, text); + view.setCatPadding(2, 1, 2, 1); + view.setCatTextSize(12); + view.setCatTextGlow(10, 0xFF000000); + view.setCatTextTFAssets("MY.ttf"); + view.setCatBackColor(0).setCatBorder(1, 0x89FFFFFF); + view.setShadowLayer(5, 2, 2, 0xFF000000); // 模糊半径为5,水平偏移2,垂直偏移2,阴影颜色为黑色 + view.setSingleLine(true); + + view.setMaxWidth(999); + view.setMaxEms(999); + // 添加渐变效果 + addMarqueeAnimation(view); + + struct.view = view; + list.add(struct); + + // 从右边挤出来的动画 + view.setTranslationX(100f); // 初始位置在右边100像素 + layout.addView(view); + ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 100f, 0f); + animator.setDuration(700); + animator.setInterpolator(new FastOutSlowInInterpolator()); + animator.start(); + + // 重新排序 + sortAndRebuildLayout(); + + return this; + } + +// 添加渐变效果的方法 + + + + + private void addMarqueeAnimation(final AlguiViewText view) { + if (view != null) { + // 定义颜色数组,用于循环渐变 + int[] colors = {0xFF00FF00,0xFF0000FF,0xFF4B0082,0xFF9400D3,0xFFFFFF00,0xFFFF7F00,0xFFFF0000,0xFF00FF00 // 红色 + // 橙色 + // 黄色 + // 绿色 + // 蓝色 + // 靛色 + // 紫色 + }; + ValueAnimator marqueeAnimator = ValueAnimator.ofArgb(colors); + marqueeAnimator.setDuration(2500); // 渐变周期为2秒 + marqueeAnimator.setRepeatCount(ValueAnimator.INFINITE); // 无限循环 + marqueeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + // 更新文本颜色 + view.setTextColor((Integer) animation.getAnimatedValue()); + view.setCatBorder(1,(Integer) animation.getAnimatedValue()); } + }); + marqueeAnimator.start(); + + } + } + + + public AlguiWinList rem(String text) { + for (int i = 0; i < list.size(); i++) { + final int index = i; // 将循环变量 i 存储为 final 变量 + final Struct struct = list.get(i); + if (struct.text.equals(text)) { + // 挤回去的动画 + ObjectAnimator animator = ObjectAnimator.ofFloat(struct.view, "translationX", 0f, 100f); + animator.setDuration(700); + animator.setInterpolator(new AccelerateDecelerateInterpolator()); + animator.addListener(new android.animation.AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(android.animation.Animator animation) { + layout.removeView(struct.view); + list.remove(struct); + // 其他元素填充到它的位置 + for (int j = index; j < list.size(); j++) { + final Struct nextStruct = list.get(j); + nextStruct.view.setTranslationY(100f); // 初始位置在下方100像素 + ObjectAnimator fillAnimator = ObjectAnimator.ofFloat(nextStruct.view, "translationY", 100f, 0f); + fillAnimator.setDuration(700); + fillAnimator.setStartDelay((j - index) * 1000); // 每个元素的动画延迟50ms + fillAnimator.setInterpolator(new DecelerateInterpolator()); + fillAnimator.start(); + } + sortAndRebuildLayout(); + } + }); + animator.start(); + break; + } + } + return this; + } + + public AlguiWinList addAndRem(String text, boolean bool) { + if (bool) { + add(text); + } else { + rem(text); + } + return this; + } + + + + private void sortAndRebuildLayout() { + // 自动判断长短 + Collections.sort(list, new Comparator() { + @Override + public int compare(Struct o1, Struct o2) { + return Integer.compare(o2.text.length(), o1.text.length()); + } + }); + + // 清除旧布局无察觉 + layout.removeAllViews(); + + // 重新启动 + for (Struct struct : list) { + layout.addView(struct.view); + } + } + + private static class Struct { + String text; + AlguiViewText view; + } +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinMenu.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinMenu.java new file mode 100644 index 0000000..c1f528b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWinMenu.java @@ -0,0 +1,1177 @@ +package com.bytecat.algui.AlguiWindows; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/12/20 18:12 + * @Describe Algui菜单窗口 + */ +import android.annotation.Nullable; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.AnimatedImageDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Message; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.Toast; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiTools.AlguiToolImage; +import com.bytecat.algui.AlguiViews.AlguiFlowLayout; +import com.bytecat.algui.AlguiViews.AlguiFrameLayout; +import com.bytecat.algui.AlguiViews.AlguiLinearLayout; +import com.bytecat.algui.AlguiViews.AlguiViewImage; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import com.bytecat.algui.AlguiViews.AlguiViewTriangle; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.view.animation.OvershootInterpolator; +import android.view.animation.AccelerateDecelerateInterpolator; +import java.util.Random; + +public class AlguiWinMenu extends AlguiFlowLayout { + + public static final String TAG = "AlguiWinMenu"; + + Context aContext;//活动 + AlguiWindow window;//窗口 + AlguiFrameLayout rootLayout;//窗口根布局 + AlguiViewImage ball;//悬浮球 + AlguiLinearLayout menu;//菜单 + AlguiLinearLayout menuTop;//菜单顶部 + AlguiFlowLayout menuNav;//菜单顶部导航栏布局(默认没有,仅占位,只有外部需要往此布局添加视图时才显示) + AlguiViewImage menuIcon;//菜单图标 + AlguiViewText menuTitle;//菜单标题 + AlguiViewImage menuEndIcon;//菜单关闭图标 + ScrollView menuList;//菜单滚动列表 + AlguiLinearLayout menuBottom;//菜单底部 + AlguiViewTriangle menuTriangle;//菜单三角视图 (菜单大小调节器) + public AlguiWindow getByteWindow() { return window; } + public AlguiFrameLayout getByteRootLayout() { return rootLayout; } + public AlguiViewImage getByteBallLayout() { return ball; } + public AlguiLinearLayout getByteMenuLayout() { return menu; } + public AlguiLinearLayout getByteMenuTopLayout() { return menuTop; } + public AlguiFlowLayout getByteMenuNavLayout() { return menuNav; } + public AlguiViewImage getByteMenuIcon() { return menuIcon; } + public AlguiViewText getByteMenuTitle() { return menuTitle; } + public AlguiViewImage getByteMenuEndIcon() { return menuEndIcon; } + public ScrollView getByteMenuList() { return menuList; } + public AlguiLinearLayout getByteMenuBottomLayout() { return menuBottom; } + public AlguiViewTriangle getByteMenuTriangle() { return menuTriangle; } + + + float winTransparent=1;//窗口透明度 + boolean isEnableWinMove=true;//是否启用窗口移动 + AlguiCallback.Click callback_MenuOpen;//回调菜单打开关闭监听 + boolean isEnableMenuSize=true;//是否启用菜单大小调节器 + boolean isEnableMenuOutsideEnd=true;//是否启用点击菜单外部可关闭菜单 + boolean isEnableTitle=true;//是否启用菜单标题栏 + boolean isShowMenu;//是否正在显示菜单 + float menuMinWidth,menuMinHeight;//菜单最小宽高 + float menuWidth,menuHeight;//菜单当前宽高 + public float getByteWinTransparent() { return winTransparent; } + public boolean isEnableWinMove() { return isEnableWinMove; } + public AlguiCallback.Click getByteMenuOpenCallback() { return callback_MenuOpen;} + public boolean isEnableMenuSize() { return isEnableMenuSize; } + public boolean isEnableMenuOutsideEnd() { return isEnableMenuOutsideEnd; } + public boolean isShowMenu() { return isShowMenu; } + public float getByteMenuMinWidth() { return menuMinWidth; } + public float getByteMenuMinHeight() { return menuMinHeight; } + public float getByteMenuWidth() { return menuWidth; } + public float getByteMenuHeight() { return menuHeight; } + + + + //------------------------------悬浮球---------------------------------------------------- + //设置悬浮球图像 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiWinMenu setCatBallImage(String Url_Base64_FilePath) { + ball.setCatImage(Url_Base64_FilePath); + return this; + } + //设置悬浮球大小 + public AlguiWinMenu setCatBallSize(int width, int height) { + ball.setCatSize(width, height); + return this; + } + //设置悬浮球透明度0-255 + public AlguiWinMenu setCatBallTransparency(int t0_255) { + ball.setCatTransparent(t0_255); + return this; + } + //设置悬浮球颜色(对于单色图像) + public AlguiWinMenu setCatBallColor(int color) { + ball.setCatColor(color); + return this; + } + //设置悬浮球毛玻璃模糊 + public AlguiWinMenu setCatBallBlur(int radius) { + ball.setCatBlur(radius); + return this; + } + //设置悬浮球圆角 + public AlguiWinMenu setCatBallRadiu(float r) { + ball.setCatRadiu(r); + return this; + } + + + + //------------------------------悬浮菜单---------------------------------------------------- + //设置菜单打开关闭监听 + public AlguiWinMenu setCatMenuOpenCallback(AlguiCallback.Click c) { + callback_MenuOpen = c; + return this; + } + + //设置菜单最小大小 + public AlguiWinMenu setCatMenuMinSize(float w, float h) { + float wPX = dp2px(w); + float hPX = dp2px(h); + menuMinWidth = wPX;menuMinHeight = hPX; + if (menuWidth < menuMinWidth) { + menuWidth = menuMinWidth; + window.getByteWindowParams().width = (int)menuWidth; + updateWin(); + } + if (menuHeight < menuMinHeight) { + menuHeight = menuMinHeight; + window.getByteWindowParams().height = (int)menuHeight; + updateWin(); + } + return this; + } + + //设置菜单大小 + public AlguiWinMenu setCatMenuSize(float w, float h) { + float wPX = dp2px(w); + float hPX = dp2px(h); + if (wPX < menuMinWidth) + wPX = menuMinWidth; + if (hPX < menuMinHeight) + hPX = menuMinHeight; + menuWidth = wPX ;menuHeight = hPX; + //在显示悬浮菜单时才应用 + if (isShowMenu) + window.setSizePX((int)menuWidth, (int)menuHeight);//应用宽高 + return this; + } + //设置菜单是否启用标题栏 + public AlguiWinMenu setCatEnableMenuTitle(boolean isEnableTitle) { + this.isEnableTitle = isEnableTitle; + if (isEnableTitle) { + menuTop.setVisibility(View.VISIBLE); + } else { + menuTop.setVisibility(View.GONE); + } + return this; + } + //设置是否启用菜单大小调节器 + public AlguiWinMenu setCatEnableMenuSize(boolean isEnableMenuSize) { + this.isEnableMenuSize = isEnableMenuSize; + if (isEnableMenuSize) { + menuTriangle.setVisibility(View.VISIBLE); + } else { + menuTriangle.setVisibility(View.GONE); + } + return this; + } + //设置是否启用点击菜单外部可关闭菜单 + public AlguiWinMenu setCatEnableMenuOutsideEnd(boolean isEnableMenuOutsideEnd) { + this.isEnableMenuOutsideEnd = isEnableMenuOutsideEnd; + if (isEnableMenuOutsideEnd) { + addWinFlag(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);//监听外部触摸 + } else { + remWinFlag(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);//移除外部触摸监听 + } + return this; + } + + //设置菜单背景图片 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiWinMenu setCatMenuBackImage(@Nullable final String Url_Base64_FilePath, final int blurRadius, final int Transparent0_255) { + if (Url_Base64_FilePath != null) { + Drawable image = AlguiToolImage.getImage(aContext, Url_Base64_FilePath, new AlguiCallback.Web(){ + //对于网络图像 + @Override + public void web(Message msg) { + switch (msg.what) { + case 200: + Object obj = msg.obj; + if (obj != null) { + if (obj instanceof Drawable) { + Drawable image = (Drawable)msg.obj; + //对于需要毛玻璃模糊 + if (blurRadius > 0) + image = AlguiToolImage.psImageBlur(image, blurRadius, aContext); + //对于需要透明度 + if (Transparent0_255 >= 0) + image.setAlpha(Transparent0_255); + image.setAlpha(Transparent0_255); + menuList.setBackground(image); + } + } + break; + case 404: + Toast.makeText(getContext(), "网络图片加载失败:服务器发生错误", Toast.LENGTH_SHORT).show(); + break; + case 651: + Toast.makeText(getContext(), "网络图片加载失败:图片异常", Toast.LENGTH_SHORT).show(); + break; + } + } + }); + //对于其它 + if (image != null) { + //对于需要毛玻璃模糊 + if (blurRadius > 0) + image = AlguiToolImage.psImageBlur(image, blurRadius, aContext); + //对于需要透明度 + if (Transparent0_255 >= 0) + image.setAlpha(Transparent0_255); + menuList.setBackground(image); + } + } else { + menuList.setBackground(null); + } + return this; + } + //______________________菜单布局______________________ + //设置菜单透明度0-1 + public AlguiWinMenu setCatMenuTransparent(float t0_1) { + menu.setAlpha(t0_1); + return this; + } + //设置菜单圆角半径 + public AlguiWinMenu setCatMenuRadiu(float radiu) { + menu.setCatRadiu(radiu); + return this; + } + //设置菜单描边 + public AlguiWinMenu setCatMenuBorder(float borderSize, int borderColor) { + menu.setCatBorder(borderSize, borderColor); + return this; + } + //设置菜单背景颜色 + public AlguiWinMenu setCatMenuBackColor(int... color) { + menu.setCatBackColor(color); + return this; + } + //______________________菜单顶部布局______________________ + //设置菜单顶部布局背景图片 (设置后圆角描边背景颜色失效,null恢复) + //参数:图片资源,毛玻璃模糊半径,透明度@0-255 + //支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + //格式:png,jpg,gif… + public AlguiWinMenu setCatMenuTopBackImage(@Nullable final String Url_Base64_FilePath, final int blurRadius, final int Transparent0_255) { + if (Url_Base64_FilePath == null) { + menuTop.setBackground(menuTop.getByteBack()); + return this; + } + //确保在布局计算完成后才设置 + menuTop.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + Drawable menuTopBackIMG;//菜单顶部布局背景图片 + public void update() { + int layoutWidth = menuTop.getWidth(); + int layoutHeight = menuTop.getHeight(); + if (menuTopBackIMG != null) { + //如果是GIF图片直接设置 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P&&menuTopBackIMG instanceof AnimatedImageDrawable) { + menuTop.setBackground((AnimatedImageDrawable) menuTopBackIMG); + } else { + //对于需要毛玻璃模糊 + if (blurRadius > 0) + menuTopBackIMG = AlguiToolImage.psImageBlur(menuTopBackIMG, blurRadius, aContext); + //对于非GIF图片进行缩放处理,图片宽超出布局宽则缩放到布局宽然后裁剪掉多余的高度部分 + Bitmap originalBitmap = AlguiToolImage.drawableToBitmap(menuTopBackIMG); + int originalWidth = originalBitmap.getWidth(); + int originalHeight = originalBitmap.getHeight(); + + // 图片与布局宽高一致直接设置 + if (layoutWidth == originalWidth && originalHeight == layoutHeight) { + menuTop.setBackground(menuTopBackIMG); + } else { + //否则将图片宽度缩放为与布局宽度一致然后裁剪掉高度多余的部分 + //计算缩放比例 + float scale = (float) layoutWidth / originalWidth; + int scaledWidth = layoutWidth; + int scaledHeight = (int) (originalHeight * scale); + + //缩放图片 + Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, scaledWidth, scaledHeight, true); + + //如果缩放后的高度超出布局高度则裁剪掉超出的高度部分 + if (scaledHeight > layoutHeight) { + //计算裁剪区域 + int cropHeight = scaledHeight - layoutHeight; + int cropStartY = cropHeight / 2; + Bitmap croppedBitmap = Bitmap.createBitmap(scaledBitmap, 0, cropStartY, scaledWidth, layoutHeight); + menuTopBackIMG = new BitmapDrawable(getResources(), croppedBitmap); + menuTop.setBackground(menuTopBackIMG); + } else { + //设置缩放后的图片为布局背景 + menuTopBackIMG = new BitmapDrawable(getResources(), scaledBitmap); + menuTop.setBackground(menuTopBackIMG); + } + } + } + if (Transparent0_255 >= 0) + menuTopBackIMG.setAlpha(Transparent0_255); + } + } + @Override + public void onGlobalLayout() { + //移除监听器以避免重复调用 + menuTop.getViewTreeObserver().removeOnGlobalLayoutListener(this); + menuTopBackIMG = AlguiToolImage.getImage(aContext, Url_Base64_FilePath, new AlguiCallback.Web(){ + //对于网络图像 + @Override + public void web(Message msg) { + switch (msg.what) { + case 200: + Object obj = msg.obj; + if (obj != null) { + if (obj instanceof Drawable) { + menuTopBackIMG = (Drawable)msg.obj; + update(); + } + } + break; + case 404: + Toast.makeText(getContext(), "网络图片加载失败:服务器发生错误", Toast.LENGTH_SHORT).show(); + break; + case 651: + Toast.makeText(getContext(), "网络图片加载失败:图片异常", Toast.LENGTH_SHORT).show(); + break; + } + } + }); + update(); + } + }); + return this; + } + //设置菜单顶部布局内边距 + public AlguiWinMenu setCatMenuTopPadding(float left, float top, float right, float bottom) { + menuTop.setCatPadding(left, top, right, bottom); + return this; + } + //设置菜单顶部布局圆角半径 + public AlguiWinMenu setCatMenuTopRadiu(float radiu) { + menuTop.setCatRadiu(radiu); + return this; + } + //设置菜单顶部布局描边 + public AlguiWinMenu setCatMenuTopBorder(float borderSize, int borderColor) { + menuTop.setCatBorder(borderSize, borderColor); + return this; + } + //设置菜单顶部布局背景颜色 + public AlguiWinMenu setCatMenuTopBackColor(int... color) { + menuTop.setCatBackColor(color); + return this; + } + + //______________________菜单图标______________________ + //设置菜单图标图像 + // 支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + // 格式:png,jpg,gif… + public AlguiWinMenu setCatMenuIconImage(@Nullable String Url_Base64_FilePath) { + if (Url_Base64_FilePath == null) { + menuIcon.setVisibility(View.GONE); + } else { + menuIcon.setCatImage(Url_Base64_FilePath); + menuIcon.setVisibility(View.VISIBLE); + } + return this; + } + //设置菜单图标颜色(对于单色图像) + public AlguiWinMenu setCatMenuIconColor(int color) { + menuIcon.setCatColor(color); + return this; + } + //设置菜单图标毛玻璃模糊 + public AlguiWinMenu setCatMenuIconBlur(int radius) { + menuIcon.setCatBlur(radius); + return this; + } + //设置菜单图标圆角 + public AlguiWinMenu setCatMenuIconRadiu(float r) { + menuIcon.setCatRadiu(r); + return this; + } + + //______________________菜单标题______________________ + //设置标题 + public AlguiWinMenu setCatMenuTitle(@Nullable CharSequence textstr, Object... args) { + if (menuTitle != null) { + menuTitle.setCatText(textstr, args); + menuTitle.setVisibility(View.VISIBLE); + } else { + menuTitle.setVisibility(View.GONE); + } + return this; + } + //设置标题颜色 + public AlguiWinMenu setCatMenuTitleColor(int... color) { + menuTitle.setCatTextColor(color); + return this; + } + //设置标题动态渐变效果启动状态 + public AlguiWinMenu setCatMenuTitleMoveGrad(boolean b) { + menuTitle.setCatTextMoveGrad(b); + return this; + } + //设置标题发光 + public AlguiWinMenu setCatMenuTitleGlow(float radius, int color) { + menuTitle.setCatTextGlow(radius, color); + return this; + } + //设置标题字体 (Assets文件夹下的字体文件名) + public AlguiWinMenu setCatMenuTitleTFAssets(String assetsTfFileName) { + menuTitle.setCatTextTFAssets(assetsTfFileName, Typeface.BOLD); + return this; + }//重载+样式 + public AlguiWinMenu setCatMenuTitleTFAssets(String assetsTfFileName, int style) { + menuTitle.setCatTextTFAssets(assetsTfFileName, style); + return this; + } + //设置标题大小 + public AlguiWinMenu setCatMenuTitleSize(float size) { + menuTitle.setCatTextSize(size);//设置文本大小 + float iconSize = size * 1.3f;//图标是标题的0.3倍 + menuIcon.setCatSize(iconSize, iconSize);//菜单图标 + //float endIconSize = size*1.1f;//关闭图标是标题的0.1倍 + menuEndIcon.setCatSize(size, size);//关闭图标 + return this; + } + //______________________菜单关闭图标______________________ + + //设置菜单关闭图标 + // 支持:网络图像链接,base64图像编码,本地图像文件,图片文件名(项目assets文件夹) + // 格式:png,jpg,gif… + public AlguiWinMenu setCatMenuEndIconImage(@Nullable String Url_Base64_FilePath) { + if (Url_Base64_FilePath == null) { + menuEndIcon.setVisibility(View.GONE); + } else { + menuEndIcon.setCatImage(Url_Base64_FilePath); + menuEndIcon.setVisibility(View.VISIBLE); + } + return this; + } + //设置菜单关闭图标颜色(对于单色图像) + public AlguiWinMenu setCatMenuEndIconColor(int color) { + menuEndIcon.setCatColor(color); + return this; + } + //设置菜单关闭图标毛玻璃模糊 + public AlguiWinMenu setCatMenuEndIconBlur(int radius) { + menuEndIcon.setCatBlur(radius); + return this; + } + //设置菜单关闭图标圆角 + public AlguiWinMenu setCatMenuEndIconRadiu(float r) { + menuEndIcon.setCatRadiu(r); + return this; + } + + //------------------------------菜单顶部导航区---------------------------------------------------- + //设置导航区方向 + public AlguiWinMenu setCatMenuNavOrientation(int orientation) { + if (menuNav != null) { + menuNav.setCatOrientation(orientation); + } + return this; + } + //设置菜单导航区内边距 + public AlguiWinMenu setCatMenuNavPadding(float left, float top, float right, float bottom) { + menuNav.setCatPadding(left, top, right, bottom); + return this; + } + //设置菜单导航区背景颜色 + public AlguiWinMenu setCatMenuNavBackColor(int... backColor) { + menuNav.setCatBackColor(backColor); + return this; + } + //设置菜单导航区圆角半径 + public AlguiWinMenu setCatMenuNavRadiu(float radiu) { + menuNav.setCatRadiu(radiu); + return this; + } + //设置菜单导航区描边 + public AlguiWinMenu setCatMenuNavBorder(float borderSize, int borderColor) { + menuNav.setCatBorder(borderSize, borderColor); + return this; + } + //设置菜单导航区一行最大视图数量 自动换行 + public AlguiWinMenu setCatMenuNavLineMaxView(int num) { + menuNav.setCatLineMaxView(num); + return this; + } + //设置菜单导航所有行的外边距 + public AlguiWinMenu setCatMenuNavLineMargins(float left, float top, float right, float bottom) { + menuNav.setCatLineMargins(left, top, right, bottom); + return this; + } + //菜单导航区 手动换行 + public AlguiLinearLayout endl_Nav() { + return menuNav.endl(); + } + //在菜单导航区 添加一些视图 中途支持换行 + public AlguiWinMenu addView_Nav(View... view) { + menuNav.addView(view); + return this; + } + //删除菜单导航区子视图 + public AlguiWinMenu remView_Nav(View... view) { + menuNav.remView(view); + return this; + } + //删除菜单导航区所有子视图 + public AlguiWinMenu remAllView_Nav() { + menuNav.removeAllViews(); + return this; + } + //删除导航区指定行的视图 + public AlguiWinMenu remViewToLine_Nav(int index, View... views) { + if (menuNav != null) { + menuNav.remViewToLine(index, views); + } + return this; + } + //删除导航区指定行 (按索引) + public AlguiWinMenu remLine_Nav(int... indexs) { + if (menuNav != null) { + menuNav.remLine(indexs); + } + return this; + } + //删除导航区指定行 (按对象) + public AlguiWinMenu remLine_Nav(AlguiLinearLayout... objs) { + if (menuNav != null) { + menuNav.remLine(objs); + } + return this; + } + //添加视图到导航区的指定行 + public AlguiWinMenu addViewToLine_Nav(int index, View... views) { + if (menuNav != null) { + menuNav.addViewToLine(index, views); + } + return this; + } + + //______________________菜单滚动列表______________________ + //设置滚动列表背景颜色 + public AlguiWinMenu setCatMenuListBackColor(int backColor) { + menuList.setBackgroundColor(backColor); + return this; + } + + //______________________菜单底部布局______________________ + //设置菜单底部布局圆角半径 + public AlguiWinMenu setCatMenuBottomRadiu(float radiu) { + menuBottom.setCatRadiu(radiu); + return this; + } + //设置菜单底部布局描边 + public AlguiWinMenu setCatMenuBottomBorder(float borderSize, int borderColor) { + menuBottom.setCatBorder(borderSize, borderColor); + return this; + } + //设置菜单底部布局背景颜色 + public AlguiWinMenu setCatMenuBottomBackColor(int... color) { + menuBottom.setCatBackColor(color); + return this; + } + + //______________________菜单右下角直角三角形______________________ + //设置菜单直角颜色 + public AlguiWinMenu setCatMenuTriangleColor(int color) { + menuTriangle.setCatColor(color); + return this; + } + //设置菜单直角大小 + public AlguiWinMenu setCatMenuTriangleSize(float size) { + menuTriangle.setCatSize(size); + return this; + } + + + + + //------------------------------菜单行缓冲区---------------------------------------------------- + //设置菜单缓冲区方向 + public AlguiWinMenu setCatMenuBufferOrientation(int orientation) { + super.setCatOrientation(orientation); + return this; + } + //设置菜单缓冲区内边距 + public AlguiWinMenu setCatMenuBufferPadding(float left, float top, float right, float bottom) { + super.setCatPadding(left, top, right, bottom); + return this; + } + //设置菜单缓冲区背景颜色 + public AlguiWinMenu setCatMenuBufferBackColor(int... backColor) { + super.setCatBackColor(backColor); + return this; + } + //设置菜单缓冲区圆角半径 + public AlguiWinMenu setCatMenuBufferRadiu(float radiu) { + super.setCatRadiu(radiu); + return this; + } + //设置菜单缓冲区描边 + public AlguiWinMenu setCatMenuBufferBorder(float borderSize, int borderColor) { + super.setCatBorder(borderSize, borderColor); + return this; + + } + //设置菜单缓冲区一行最大视图数量 自动换行 + public AlguiWinMenu setCatMenuBufferLineMaxView(int num) { + super.setCatLineMaxView(num); + return this; + } + //设置菜单缓冲区所有行的外边距 + public AlguiWinMenu setCatMenuBufferLineMargins(float left, float top, float right, float bottom) { + super.setCatLineMargins(left, top, right, bottom); + return this; + } + + //缓冲区 手动换行 + public AlguiLinearLayout endl() { + return super.endl(); + } + //在缓冲区 添加一些视图 中途null代表换行 + public AlguiWinMenu addView(View... view) { + super.addView(view); + return this; + } + //删除缓冲区子视图 + public AlguiWinMenu remView(View... view) { + super.remView(view); + return this; + } + //删除缓冲区所有子视图 + public AlguiWinMenu remAllView() { + super.remAllView(); + return this; + } + //删除缓冲区指定行的视图 + public AlguiWinMenu remViewToLine(int index, View... views) { + super.remViewToLine(index, views); + return this; + } + //删除缓冲区指定行 (按索引) + public AlguiWinMenu remLine(int... indexs) { + super.remLine(indexs); + return this; + } + //删除缓冲区指定行 (按对象) + public AlguiWinMenu remLine(AlguiLinearLayout... objs) { + super.remLine(objs); + return this; + } + //添加视图到缓冲区的指定行 + public AlguiWinMenu addViewToLine(int index, View... views) { + super.addViewToLine(index, views); + return this; + } + + + + + //------------------------------主窗口---------------------------------------------------- + //设置窗口显示在哪个活动中 + //如果传入Activity则仅悬浮显示在这一个活动中(无需悬浮窗权限) + //传入后台Context则全局悬浮显示(需悬浮窗权限) + public AlguiWinMenu setCatWinActivity(Context context) { + if (context != null) { + aContext = context; + window.setCatActivity(context); + } + return this; + } + //显示窗口 + public AlguiWinMenu showWin() { + window.show(); + expandMenu(); + return this; + } + //更新窗口 + public AlguiWinMenu updateWin() { + window.update(); + return this; + } + //隐藏窗口 + public AlguiWinMenu hideWin() { + setCatWinView(null); + window.hide(); + collapseMenu(); + return this; + } + //设置窗口布局视图 (只能容纳一个视图) + public AlguiWinMenu setCatWinView(View view) { + rootLayout.remAllView();//清除窗口根布局所有视图 + if (view != null) + rootLayout.addView(view); + showWin(); + return this; + } + //设置一些窗口特性 + public AlguiWinMenu setCatWinFlags(int flags) { + window.setCatFlags(flags); + return this; + } + //添加一个窗口特性 + public AlguiWinMenu addWinFlag(int flag) { + window.addFlag(flag); + return this; + } + //移除一个窗口特性 + public AlguiWinMenu remWinFlag(int flag) { + window.remFlag(flag); + return this; + } + //设置是否启用窗口动态移动 + public AlguiWinMenu setCatEnableWinMove(boolean isEnableWinMove) { + this.isEnableWinMove = isEnableWinMove; + return this; + } + //设置窗口在屏幕上的xy位置 (相对左上角原点xy偏移) + public AlguiWinMenu setCatWinPos(float x, float y) { + window.setCatPos(x, y); + return this; + } + //设置窗口亮度0-1 + public AlguiWinMenu setCatWinBrightness(float b0_1) { + window.setCatBrightness(b0_1); + return this; + } + //设置窗口透明度0-1 + public AlguiWinMenu setCatWinTransparent(float t0_1) { + window.setCatTransparent(t0_1); + winTransparent = t0_1; + return this; + } + //设置窗口启动退出动画 + public AlguiWinMenu setCatWinAnimations(int animID) { + window.setCatAnimations(animID); + return this; + } + //显示悬浮球 + public AlguiWinMenu showBall() { + //窗口添加无法获取输入焦点的flag 防止显示悬浮球时窗口之外无法弹出输入法 + addWinFlag(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); + //窗口移除允许显示在屏幕之外的flag + remWinFlag(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + //只有悬浮球根布局未添加时才添加 + if (rootLayout.indexOfChild(ball) == -1) { + //窗口宽高跟随悬浮球大小 + window.setSizePX(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT); + setCatWinView(ball); + } + isShowMenu = false; + if (callback_MenuOpen != null) + callback_MenuOpen.click(isShowMenu); + return this; + } + //显示悬浮菜单 + public AlguiWinMenu showMenu() { + //窗口添加允许显示在屏幕之外的flag + addWinFlag(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + //窗口移除无法获取输入焦点的flag 防止菜单输入框无法弹出输入法 但这会使窗口之外无法弹出输入法 + remWinFlag(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); + //只有菜单根布局未添加时才添加 + if (rootLayout.indexOfChild(menu) == -1) { + //窗口宽高是上次的菜单宽高 + window.setSizePX((int)menuWidth, (int)menuHeight); + setCatWinView(menu); + } + isShowMenu = true; + if (callback_MenuOpen != null) + callback_MenuOpen.click(isShowMenu); + return this; + } + + + + //------------------------------初始化---------------------------------------------------- + public AlguiWinMenu(Context context) { + super(context); + aContext = context; + + initWindow();//初始化窗口 + initBallLayout();//初始化悬浮球 + initMenu();//初始化菜单 + + setCatWinActivity(aContext);//设置窗口显示 + setCatMenuMinSize(100, 100);//设置最小宽高 + setCatMenuSize(200, 200);//设置宽高 + setCatWinAnimations(AlguiWindow.Animations.Animation_Translucent);//启动退出动画 + } + public AlguiWinMenu(Context context, CharSequence title) { + this(context); + setCatMenuTitle(title); + } + + //初始化窗口 + private void initWindow() { + //窗口 + window = new AlguiWindow(aContext); + //设置特性 + window.setCatFlags( + WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED//硬件加速 + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL//不阻止其他窗口接收触摸事件 + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH//监听窗口外部触摸 + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE//无法获取输入框焦点 + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS//允许显示在屏幕之外 + ); + + //窗口根布局 + rootLayout = new AlguiFrameLayout(aContext); + rootLayout.setCatBackColor(Color.TRANSPARENT); + rootLayout.setLayerType(View.LAYER_TYPE_HARDWARE, null) ;//开启硬件加速减少延迟 + window.setCatView(rootLayout);//设置窗口根布局 + + //设置窗口触摸移动事件 + rootLayout.setOnTouchListener( + new OnTouchListener() { + private int signX; + private int signY; + private float downX; + private float downY; + private float moveX; + private float moveY; + boolean isOne=true;//第一次移动 + boolean isMove=false;//当前是否在移动 + int moveThreshold=20;//手指移动的阀值 (灵敏度) 改小更容易触发移动 太小可能导致误判打不开悬浮窗 + @Override + public boolean onTouch(View view, MotionEvent event) { + + switch (event.getActionMasked()) { + //点击了窗口之外的区域时触发 + case MotionEvent.ACTION_OUTSIDE: + if (isEnableMenuOutsideEnd) { + //正在显示菜单则显示悬浮球 + if (isShowMenu) + showBall(); + + } + return true; + //手指按下时触发 + case MotionEvent.ACTION_DOWN: + isMove = false; + + if (isEnableWinMove) { + isOne = true; + signX = window.getByteWindowParams().x;//记录窗口初始位置的横向坐标 + signY = window.getByteWindowParams().y;//记录窗口初始位置的竖向坐标 + downX = event.getRawX();//记录手指按下时的绝对横向坐标 + downY = event.getRawY();//记录手指按下时的绝对竖向坐标 + } + + return true; + //手指移动时触发 + case MotionEvent.ACTION_MOVE: + if (isEnableWinMove) { + float moveDistanceX = Math.abs(event.getRawX() - downX); + float moveDistanceY = Math.abs(event.getRawY() - downY); + if (moveDistanceX > moveThreshold || moveDistanceY > moveThreshold) { + isMove = true;//当前是移动 + } + if (isMove) { + //第一次移动执行的内容 + if (isOne) { + rootLayout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);//窗口进行移动触觉振动反馈 + window.setCatTransparent(winTransparent / 2); + isOne = false;//不是第一次移动了 + } + window.getByteWindowParams().x = signX + (int) (event.getRawX() - downX);//根据手指移动的距离计算窗口新的横向坐标 + window.getByteWindowParams().y = signY + (int) (event.getRawY() - downY);//根据手指移动的距离计算窗口新的竖向坐标 + window.update();//更新窗口位置 + } + } + + return true; + //手指抬起时触发 + case MotionEvent.ACTION_UP: + if (!isMove) { + //不是移动状态 而是点击抬起的 + //正在显示悬浮球则显示菜单 + if (!isShowMenu) { + //AlguiAudioBase64.play(AlguiAudioBase64.Window_on);//播放菜单显示音频 + showMenu();//显示菜单 + + } + } else { + window.setCatTransparent(winTransparent); + } + return true; + } + return false; + } + } + ); + } + + private void expandMenu() { + // 创建透明度动画 + ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(rootLayout, "alpha", 0f, 1f); + + // 创建颜色过渡动画 + ObjectAnimator colorAnimator = ObjectAnimator.ofArgb(rootLayout, "backgroundColor", 0x0000, 0x00000); + + // 创建动画集合 + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether(alphaAnimator, colorAnimator); + + // 设置动画时长和插值器 + animatorSet.setDuration(700); + animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); + + // 启动动画 + animatorSet.start(); + } + + private void collapseMenu() { + // 创建透明度动画 + ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(rootLayout, "alpha", 1f, 0f); + + // 创建颜色过渡动画 + ObjectAnimator colorAnimator = ObjectAnimator.ofArgb(rootLayout, "backgroundColor", 0x0000, 0x00000); + + // 创建动画集合 + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether(alphaAnimator, colorAnimator); + + // 设置动画时长和插值器 + animatorSet.setDuration(700); + animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); + + // 启动动画 + animatorSet.start(); + } + //初始化悬浮球 + private void initBallLayout() { + ball = new AlguiViewImage(aContext) + .setCatColor(0xff294A7A) + .setCatSize(40, 40) + ; + //默认使用当前应用图标 + try { + String packageName = aContext.getPackageName();//获取当前应用的包名 + PackageManager packageManager = aContext.getPackageManager();//获取包管理器 + Drawable appIcon = packageManager.getApplicationIcon(packageName);//获取应用的图标 + if (appIcon != null) + ball.setCatDrawable(appIcon);//使用当前应用图标 + else + ball.setCatImage(AlguiAssets.Icon.round);//使用圆 + + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + //初始化菜单 + private void initMenu() { + //菜单根布局 + menu = new AlguiLinearLayout(aContext); + menu.setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); + menu.setOrientation(LinearLayout.VERTICAL); + menu.setCatBorder(0.4f, 0xFF424242); + menu.setCatBackColor(0xff151617); + menu.setAlpha(1f); + + //顶部布局 + menuTop = new AlguiLinearLayout(aContext); + menuTop.setCatSize( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + menuTop.setOrientation(LinearLayout.HORIZONTAL); + menuTop.setGravity(Gravity.CENTER_VERTICAL); + menuTop.setCatBackColor(0xff294A7A); + menuTop.setCatPadding(2, 2, 2, 2); + + //顶部导航栏布局(默认没有,仅先占位,只有外部需要时往此布局添加视图时才显示) + menuNav = new AlguiFlowLayout(aContext); + menuNav.setCatSize(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + menuNav.setCatWeight(0); + menuNav.setCatBackColor(0xff151617); + + //图标 + menuIcon = new AlguiViewImage(aContext); + menuIcon.setCatMargins(0, 0, 2, 0); + menuIcon.setCatSize(10, 10); + menuIcon.setCatColor(0xffADB1B7); + menuIcon.setVisibility(View.GONE);//默认隐藏 + //默认使用当前应用图标 + /*try { + String packageName = aContext.getPackageName();//获取当前应用的包名 + PackageManager packageManager = aContext.getPackageManager();//获取包管理器 + Drawable appIcon = packageManager.getApplicationIcon(packageName);//获取应用的图标 + if (appIcon != null) + menuIcon.setCatDrawable(appIcon);//使用当前应用图标 + else + menuIcon.setCatImage(AlguiAssets.Icon.round);//使用圆 + + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + }*/ + + + + + //标题 + menuTitle = new AlguiViewText(aContext); + menuTitle.setCatSize(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + menuTitle.setCatWeight(1); + menuTitle.setCatMargins(2, 0, 0, 0); + menuTitle.setCatText(TAG); + menuTitle.setCatTextTFAssets(null, Typeface.BOLD); //粗体 + menuTitle.setCatTextSize(7); + menuTitle.setCatTextColor(0xffADB1B7); + + //关闭图标 + menuEndIcon = new AlguiViewImage(aContext, AlguiAssets.Icon.fork); + menuEndIcon.setCatMargins(0, 0, 2, 0); + menuEndIcon.setCatSize(7, 7); + menuEndIcon.setCatColor(0xffADB1B7); + menuEndIcon.setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + showBall(); + } + } + ); + + //滚动列表 + menuList = new ScrollView(aContext); + menuList.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT, 1f)); + + //底部布局 + menuBottom = new AlguiLinearLayout(aContext); + menuBottom.setCatSize( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + menuBottom.setOrientation(LinearLayout.HORIZONTAL);//横向 + menuBottom.setGravity(Gravity.CENTER_VERTICAL | Gravity.END); + + + //三角形 (窗口大小调节器) + menuTriangle = new AlguiViewTriangle(aContext); + menuTriangle.setCatSize(13);//大小 + menuTriangle.setCatColor(0xff1E3045);//颜色 + menuTriangle.setCatType(AlguiViewTriangle.Type.RIGHT_ANGLE_RIGHT_BOTTOM);//类型为右下直角 + + //菜单三角形触摸监听 调整窗口大小 + menuTriangle.setOnTouchListener(new View.OnTouchListener(){ + + //用于存储手指按下时的坐标 + private float downInitX, downInitY; + //用于存储手指按下时窗口的宽高 + private float winW,winH; + private LinearLayout.LayoutParams menuRootLayoutParams; + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + //手指按下时触发 + case MotionEvent.ACTION_DOWN: + //记录现在手指按下时的初始坐标 + downInitX = event.getRawX(); + downInitY = event.getRawY(); + //记录窗口按下时的宽高 + winW = window.getByteWindowParams().width; + winH = window.getByteWindowParams().height; + return true; + //手指移动时触发 + case MotionEvent.ACTION_MOVE: + //计算现在移动时坐标相对于手指按下时坐标的偏移量 现在移动时的手指坐标减去手指按下时的坐标=偏移量(移动距离) + int offsetX = (int) (event.getRawX() - downInitX); + int offsetY = (int) (event.getRawY() - downInitY); + + //为菜单布局设置新的宽高 参数1为最小宽高 新的宽高:初始宽高 + 手指移动后的偏移量 = 新的宽高 + menuWidth = Math.max(menuMinWidth, winW + offsetX); + menuHeight = Math.max(menuMinHeight, winH + offsetY); + window.setSizePX((int)menuWidth, (int)menuHeight);//更新大小 + //debug + /* debugText.setCatText("initW:" + winW + " | " + "initH:" + winH + "\n" + + "width:" + menuWidth + " | " + "height:" + menuHeight + );*/ + return true; + //手指抬起时触发 + case MotionEvent.ACTION_UP: + + return true; + } + return false; + } + }); + + //顶部布局 + menuTop.addView(menuIcon, menuTitle, menuEndIcon); + //滚动列表 + menuList.addView(this); + //底部布局 + menuBottom.addView(menuTriangle); + + //构造菜单整体布局 + menu.addView(menuTop); + menu.addView(menuNav); + menu.addView(menuList); + menu.addView(menuBottom); + + } + + + //导航 + /*private Map titleLayouts = new HashMap<>(); + + //添加导航 + public AlguiWinMenu addNav(String... titles) { + for (String title : titles) { + if (title != null && !title.isEmpty()) { + if (!titleLayouts.containsKey(title)) { + AlguiButton button = new AlguiButton(aContext, title); + + final AlguiFlowLayout layout = new AlguiFlowLayout(aContext); + button.setCatCallback(new AlguiCallback.Click(){ + public void click(boolean b) { + remAllView(); + if(layout!=null) + addView(layout); + endl(); + } + } + ); + addView_Nav(button); + titleLayouts.put(title, layout); + } + } else { + System.out.println("无效标题"); + } + } + return this; + } + + //向对应导航布局添加视图 + public void addView(String title, View... view) { + AlguiFlowLayout layout = titleLayouts.get(title); + if (layout != null) { + layout.addView(view); + } + }*/ + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWindow.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWindow.java new file mode 100644 index 0000000..ceebb30 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/AlguiWindow.java @@ -0,0 +1,318 @@ +package com.bytecat.algui.AlguiWindows; +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.Build; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import com.bytecat.algui.AlguiTools.AlguiToolPermission; + +/** + * @Author 作者:𝗕𝘆𝘁𝗲𝗖𝗮𝘁* - [Copyright © 2024 𝗕𝘆𝘁𝗲𝗖𝗮𝘁 版权所有]游戏逆向交流群730967224 - 作者QQ3353484607 + * @Date 2024/09/17 23:44 + * @Describe Algui窗口 + */ +public class AlguiWindow { + + public static final String TAG = "AlguiWindow"; + + //窗口启动退出动画 + public static class Animations { + public static final int Animation = 0x1030000 /*16973824*/;//默认 + public static final int Animation_Activity = 0x1030001 /*16973825*/;//弹出(活动) + public static final int Animation_Dialog = 0x1030002 /*16973826*/;//弹出(弹窗) + public static final int Animation_InputMethod = 0x1030056 /*16973910*/;//下移上(键盘) + public static final int Animation_Toast = 0x1030004 /*16973828*/;//弹出(弹窗) + public static final int Animation_Translucent = 0x1030003 /*16973827*/;//右移左 + } + + + Context aContext; + boolean isWindowShow = false;//窗口是否正在显示 + WindowManager Window;//窗口 + WindowManager.LayoutParams WindowParams;//窗口参数 + View view;//显示的视图 + + //get-set拓展方法 + // 获取上下文 + public Context getByteContext() { + return aContext; + } + + + + // 获取窗口管理器 + public WindowManager getByteWindowManager() { + return Window; + } + + // 获取窗口参数 + public WindowManager.LayoutParams getByteWindowParams() { + return WindowParams; + } + + // 设置窗口参数 + public AlguiWindow setCatWindowParams(WindowManager.LayoutParams windowParams) { + if (windowParams != null) { + this.WindowParams = windowParams; + update(); + } else { + hide(); + } + return this; + } + + // 获取显示的视图 + public View getByteView() { + return view; + } + + //设置视图 + public AlguiWindow setCatView(View view) { + if (view == null) { + hide(); + } + this.view = view; + // show(); + update(); + return this; + } + + // 获取窗口是否正在显示 + public boolean isWindowShow() { + return isWindowShow; + } + + + //设置窗口显示在哪个活动中 + //如果传入Activity则仅悬浮显示在这一个活动中(无需悬浮窗权限) + //传入后台Context则全局悬浮显示(需悬浮窗权限) + public AlguiWindow setCatActivity(Context context) { + if (context != null) { + aContext = context; + boolean b =isWindowShow;//保存之前是否正在显示状态 + hide();//先清除视图 + + //设置窗口类型 + if (aContext instanceof Activity) { + //对于上下文为活动时 窗口类型设置为应用级窗口 (无需悬浮窗权限) + WindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION; + } else { + //对于其它 则使用系统级后台全局窗口 (需要悬浮窗权限) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + //对于安卓8.0以上 + WindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + } else { + //对于安卓8.0以下 + WindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; + } + //申请悬浮窗权限 + AlguiToolPermission.getWindow(context); + } + //获取窗口实例 + Window = (WindowManager) aContext.getSystemService(Context.WINDOW_SERVICE); + + //之前正在显示则重新显示 + if (b) { + show(); + } + } else { + hide(); + } + return this; + } + + //初始化时传递的Context决定窗口显示在哪里, + //如果传入Activity则仅悬浮显示在这一个活动中(无需悬浮窗权限) + //传入后台Context则全局悬浮显示(需悬浮窗权限) + //之后也可以通过setCatActivity方法更改显示 + public AlguiWindow(Context context) { + aContext = context; + init(); + setCatActivity(aContext); + } + + public AlguiWindow(Context context, View view) { + this(context); + setCatView(view); + } + + + + //显示 + public AlguiWindow show() { + //未显示才显示 + if (!isWindowShow && view != null) { + //对于安卓8.0以下无需悬浮窗权限 + Window.addView(view, WindowParams); + isWindowShow = true; + } + return this; + } + //更新 + public AlguiWindow update() { + //正在显示才更新 + if (isWindowShow && view != null) { + Window.updateViewLayout(view, WindowParams); + } + return this; + } + //隐藏 + public AlguiWindow hide() { + //正在显示才清除 + if (isWindowShow && view != null) { + Window.removeView(view); + isWindowShow = false; + } + return this; + } + + //设置一些窗口特性 + public AlguiWindow setCatFlags(int flags) { + WindowParams.flags = flags; + update(); + return this; + } + //添加一个窗口特性 + public AlguiWindow addFlag(int flag) { + //只有在没有此flag时才添加 + if ((WindowParams.flags & flag) == 0) { + WindowParams.flags |= flag; + update(); + } + return this; + } + //移除一个窗口特性 + public AlguiWindow remFlag(int flag) { + //只有窗口存在此flag时才移除 + if ((WindowParams.flags & flag) != 0) { + WindowParams.flags &= ~flag; + update(); + } + return this; + } + + //设置窗口大小(dp单位 大小适应不同设备) + public AlguiWindow setCatSize(float w, float h) { + if ((int)w != WindowManager.LayoutParams.WRAP_CONTENT + && (int) w != WindowManager.LayoutParams.MATCH_PARENT + && (int)w != WindowManager.LayoutParams.FILL_PARENT) { + WindowParams.width = (int)dp2px(w); + } else { + WindowParams.width = (int)w; + } + + if ((int)h != WindowManager.LayoutParams.WRAP_CONTENT + && (int)h != WindowManager.LayoutParams.MATCH_PARENT + && (int)h != WindowManager.LayoutParams.FILL_PARENT) { + WindowParams.height = (int)dp2px(h); + } else { + WindowParams.height = (int)h; + } + update(); + return this; + } + //设置窗口大小(px单位) + public AlguiWindow setSizePX(int w, int h) { + WindowParams.width = w; + WindowParams.height = h; + update(); + return this; + } + //设置窗口相对于屏幕哪个位置(设置坐标原点) + public AlguiWindow setCatPosGravity(int gravity) { + WindowParams.gravity = gravity ; + update(); + return this; + } + //设置窗口在屏幕上的xy位置 (相对Gravity原点的xy偏移) + public AlguiWindow setCatPos(float x, float y) { + WindowParams.x = (int) dp2px(x); + WindowParams.y = (int) dp2px(y); + update(); + return this; + } + //设置窗口在屏幕上的xy位置(相对Gravity原点的xy偏移) + public AlguiWindow setPos(int x, int y) { + WindowParams.x = x; + WindowParams.y = y; + update(); + return this; + } + //设置窗口亮度0-1 + public AlguiWindow setCatBrightness(float b0_1) { + WindowParams.screenBrightness = b0_1; + update(); + return this; + } + //设置窗口透明度0-1 + public AlguiWindow setCatTransparent(float t0_1) { + WindowParams.alpha = t0_1; + update(); + return this; + } + //设置窗口启动退出动画 + public AlguiWindow setCatAnimations(int animID) { + WindowParams.windowAnimations = animID; + update(); + return this; + } + + + + private void init() { + //窗口默认参数 + WindowParams = new WindowManager.LayoutParams(); + WindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; + WindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + WindowParams.gravity = Gravity.TOP | Gravity.LEFT;//位于父布局(屏幕)的位置 (原点)默认左上角 + WindowParams.format = PixelFormat.RGBA_8888;//像素格式 + WindowParams.flags = + WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED//硬件加速 + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL//不阻止其他窗口接收触摸事件 + //| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH//监听窗口外部触摸 + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE//无法获取输入框焦点 + ; + + //WindowManager.LayoutParams-API: + /*public float alpha; // 窗口的透明度,范围是0.0到1.0,0.0表示完全透明,1.0表示完全不透明。 + public float buttonBrightness; // 按钮的亮度调节,控制窗口中按钮的亮度,通常用于系统窗口的按钮显示。 + public float dimAmount; // 窗口的暗度,范围是0.0到1.0,0.0表示完全亮,1.0表示完全黑暗。常用于设置窗口暗背景。 + public int flags; // 窗口的标志位,控制窗口的特性和行为。通过位掩码设置不同的窗口行为,如是否可以获得焦点、是否需要显示在最上层等。 + public int format; // 窗口内容的像素格式,通常指定显示内容的颜色格式。 + public int gravity; // 窗口的重力布局参数,确定窗口相对于父容器的对齐方式。比如,可以指定窗口对齐方式为左上、居中等。 + public float horizontalMargin; // 窗口水平方向的外边距,通常用于调整窗口在水平轴上的位置。 + @ViewDebug.ExportedProperty public float horizontalWeight; // 水平权重,用于多窗口的布局管理,决定窗口在水平方向上的扩展比例。 + public int layoutInDisplayCutoutMode; // 窗口显示是否适应显示切口区域。对于有刘海屏的设备,可以控制窗口是否允许显示在切口区域内。 + @Deprecated public int memoryType; // 窗口的内存类型,已被废弃。用于指定窗口使用的内存类型(如屏幕外内存、系统内存等)。 + public String packageName; // 设置窗口所属的应用程序包名,通常用于多任务系统,标识窗口属于哪个应用。 + public int preferredDisplayModeId; // 偏好的显示模式ID,指示窗口的显示模式(如高刷新率模式等)。 + @Deprecated public float preferredRefreshRate; // 偏好的刷新率,已被废弃。指定窗口显示的刷新率。 + public int rotationAnimation; // 窗口旋转动画的方式。控制窗口在旋转时是否需要动画效果以及动画的类型。 + public float screenBrightness; // 屏幕亮度,控制窗口所显示的屏幕的亮度,范围通常是0.0到1.0。 + public int screenOrientation; // 屏幕的方向,可以是 `ActivityInfo.SCREEN_ORIENTATION_*` 常量之一,表示窗口显示时的方向,如竖屏、横屏等。 + public int softInputMode; // 控制软键盘行为的标志位,设置窗口显示时,软键盘如何弹出和交互。 + public int systemUiVisibility; // 控制窗口的系统UI显示状态,例如是否显示状态栏、导航栏等。 + public IBinder token; // 窗口的标识符,通常是一个 `IBinder` 对象,表示窗口所属的上下文或者 Activity,帮助系统识别这个窗口属于哪个任务。 + public int type; // 窗口类型,指定窗口的种类,比如普通窗口、系统窗口、浮动窗口等,决定窗口的表现和优先级。 + public float verticalMargin; // 窗口垂直方向的外边距,调整窗口在垂直轴上的位置。 + @ViewDebug.ExportedProperty public float verticalWeight; // 垂直权重,用于多窗口的布局管理,决定窗口在垂直方向上的扩展比例。 + public int windowAnimations; // 窗口的动画资源ID,控制窗口显示、隐藏时的动画效果。 + @ViewDebug.ExportedProperty public int x; // 窗口的水平坐标,指定窗口相对于屏幕或父容器的水平位置。 + @ViewDebug.ExportedProperty public int y; // 窗口的垂直坐标,指定窗口相对于屏幕或父容器的垂直位置。 + */ + } + + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public float dp2px(float dpValue) { + //参数:输入值单位,需转换的值,设备显示信息 + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, Resources.getSystem().getDisplayMetrics()); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/AlguiWindows/RC4Util.java b/app/src/main/java/com/bytecat/algui/AlguiWindows/RC4Util.java new file mode 100644 index 0000000..a1c37f2 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/AlguiWindows/RC4Util.java @@ -0,0 +1,161 @@ +package com.bytecat.algui.AlguiWindows; +import java.io.UnsupportedEncodingException; + +/** + * RC4加密算法 + */ +public class RC4Util { + + public static String encryRC4String(String variableName, String rc4Key) { + return null; + } + /** + * RC4加密,将加密后的数据进行哈希 + * + * @param data 需要加密的数据 + * @param key 加密密钥 + * @param chartSet 编码方式 + * @return 返回加密后的数据 + * @throws UnsupportedEncodingException + */ + public static String encryRC4String(String data, String key, String chartSet) throws UnsupportedEncodingException { + if (data == null || key == null) { + return null; + } + return bytesToHex(encryRC4Byte(data, key, chartSet)); + } + + /** + * RC4加密,将加密后的字节数据 + * + * @param data 需要加密的数据 + * @param key 加密密钥 + * @param chartSet 编码方式 + * @return 返回加密后的数据 + * @throws UnsupportedEncodingException + */ + public static byte[] encryRC4Byte(String data, String key, String chartSet) throws UnsupportedEncodingException { + if (data == null || key == null) { + return null; + } + if (chartSet == null || chartSet.isEmpty()) { + byte bData[] = data.getBytes(); + return RC4Base(bData, key); + } else { + byte bData[] = data.getBytes(chartSet); + return RC4Base(bData, key); + } + } + + /** + * RC4解密 + * + * @param data 需要解密的数据 + * @param key 加密密钥 + * @param chartSet 编码方式 + * @return 返回解密后的数据 + * @throws UnsupportedEncodingException + */ + public static String decryRC4(String data, String key, String chartSet) throws UnsupportedEncodingException { + if (data == null || key == null) { + return null; + } + return new String(RC4Base(hexToByte(data), key), chartSet); + } + + /** + * RC4加密初始化密钥 + * + * @param aKey + * @return + */ + private static byte[] initKey(String aKey) { + byte[] bkey = aKey.getBytes(); + byte state[] = new byte[256]; + + for (int i = 0; i < 256; i++) { + state[i] = (byte) i; + } + int index1 = 0; + int index2 = 0; + if (bkey.length == 0) { + return null; + } + for (int i = 0; i < 256; i++) { + index2 = ((bkey[index1] & 0xff) + (state[i] & 0xff) + index2) & 0xff; + byte tmp = state[i]; + state[i] = state[index2]; + state[index2] = tmp; + index1 = (index1 + 1) % bkey.length; + } + return state; + } + + + /** + * 字节数组转十六进制 + * + * @param bytes + * @return + */ + public static String bytesToHex(byte[] bytes) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + String hex = Integer.toHexString(bytes[i] & 0xFF); + if (hex.length() < 2) { + sb.append(0); + } + sb.append(hex); + } + return sb.toString(); + } + + /** + * 十六进制转字节数组 + * + * @param inHex + * @return + */ + public static byte[] hexToByte(String inHex) { + int hexlen = inHex.length(); + byte[] result; + if (hexlen % 2 == 1) { + hexlen++; + result = new byte[(hexlen / 2)]; + inHex = "0" + inHex; + } else { + result = new byte[(hexlen / 2)]; + } + int j = 0; + for (int i = 0; i < hexlen; i += 2) { + result[j] = (byte) Integer.parseInt(inHex.substring(i, i + 2), 16); + j++; + } + return result; + } + + /** + * RC4解密 + * + * @param input + * @param mKkey + * @return + */ + private static byte[] RC4Base(byte[] input, String mKkey) { + int x = 0; + int y = 0; + byte key[] = initKey(mKkey); + int xorIndex; + byte[] result = new byte[input.length]; + for (int i = 0; i < input.length; i++) { + x = (x + 1) & 0xff; + y = ((key[x] & 0xff) + y) & 0xff; + byte tmp = key[x]; + key[x] = key[y]; + key[y] = tmp; + xorIndex = ((key[x] & 0xff) + (key[y] & 0xff)) & 0xff; + result[i] = (byte) (input[i] ^ key[xorIndex]); + } + return result; + } +} diff --git a/app/src/main/java/com/bytecat/algui/CrashHandlerActivity.java b/app/src/main/java/com/bytecat/algui/CrashHandlerActivity.java new file mode 100644 index 0000000..a1e77af --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/CrashHandlerActivity.java @@ -0,0 +1,31 @@ +package com.bytecat.algui; + +import android.app.Activity; +import android.os.Bundle; +import android.view.ViewGroup; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.Toast; + +public class CrashHandlerActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final String stackTrace = getIntent().getStringExtra("stackTrace"); + + final ScrollView scrollView = new ScrollView(this); + final TextView textView = new TextView(this); + textView.setText(stackTrace); + textView.setTextSize(16f); + textView.setTextIsSelectable(true); + scrollView.addView(textView); + + addContentView(scrollView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + + @Override + public void onBackPressed() { + Toast.makeText(this, "软件已崩溃,不允许返回", Toast.LENGTH_SHORT).show(); + } +} diff --git a/app/src/main/java/com/bytecat/algui/GlobalApplication.java b/app/src/main/java/com/bytecat/algui/GlobalApplication.java new file mode 100644 index 0000000..be63697 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/GlobalApplication.java @@ -0,0 +1,334 @@ +package com.bytecat.algui; + +import android.app.Activity; +import android.app.Application; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.res.Resources; +import android.graphics.Typeface; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.Toast; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.Thread.UncaughtExceptionHandler; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +public class GlobalApplication extends Application { + + private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper()); + + @Override + public void onCreate() { + super.onCreate(); + CrashHandler.getInstance().registerGlobal(this); + CrashHandler.getInstance().registerPart(this); + } + + public static void write(InputStream input, OutputStream output) throws IOException { + byte[] buf = new byte[1024 * 8]; + int len; + while ((len = input.read(buf)) != -1) { + output.write(buf, 0, len); + } + } + + public static void write(File file, byte[] data) throws IOException { + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) parent.mkdirs(); + + ByteArrayInputStream input = new ByteArrayInputStream(data); + FileOutputStream output = new FileOutputStream(file); + try { + write(input, output); + } finally { + closeIO(input, output); + } + } + + public static String toString(InputStream input) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + write(input, output); + try { + return output.toString("UTF-8"); + } finally { + closeIO(input, output); + } + } + + public static void closeIO(Closeable... closeables) { + for (Closeable closeable : closeables) { + try { + if (closeable != null) closeable.close(); + } catch (IOException ignored) {} + } + } + + public static class CrashHandler { + + public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler(); + + private static CrashHandler sInstance; + + private PartCrashHandler mPartCrashHandler; + + public static CrashHandler getInstance() { + if (sInstance == null) { + sInstance = new CrashHandler(); + } + return sInstance; + } + + public void registerGlobal(Context context) { + registerGlobal(context, null); + } + + public void registerGlobal(Context context, String crashDir) { + Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl(context.getApplicationContext(), crashDir)); + } + + public void unregister() { + Thread.setDefaultUncaughtExceptionHandler(DEFAULT_UNCAUGHT_EXCEPTION_HANDLER); + } + + public void registerPart(Context context) { + unregisterPart(context); + mPartCrashHandler = new PartCrashHandler(context.getApplicationContext()); + MAIN_HANDLER.postAtFrontOfQueue(mPartCrashHandler); + } + + public void unregisterPart(Context context) { + if (mPartCrashHandler != null) { + mPartCrashHandler.isRunning.set(false); + mPartCrashHandler = null; + } + } + + private static class PartCrashHandler implements Runnable { + + private final Context mContext; + + public AtomicBoolean isRunning = new AtomicBoolean(true); + + public PartCrashHandler(Context context) { + this.mContext = context; + } + + @Override + public void run() { + while (isRunning.get()) { + try { + Looper.loop(); + } catch (final Throwable e) { + e.printStackTrace(); + if (isRunning.get()) { + MAIN_HANDLER.post(new Runnable(){ + + @Override + public void run() { + Toast.makeText(mContext, e.toString(), Toast.LENGTH_LONG).show(); + } + }); + } else { + if (e instanceof RuntimeException) { + throw (RuntimeException)e; + } else { + throw new RuntimeException(e); + } + } + } + } + } + } + + private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler { + + private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss"); + + private final Context mContext; + + private final File mCrashDir; + + public UncaughtExceptionHandlerImpl(Context context, String crashDir) { + this.mContext = context; + this.mCrashDir = TextUtils.isEmpty(crashDir) ? new File(mContext.getExternalCacheDir(), "crash") : new File(crashDir); + } + + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + try { + + String log = buildLog(throwable); + writeLog(log); + + try { + Intent intent = new Intent(mContext, CrashActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(Intent.EXTRA_TEXT, log); + mContext.startActivity(intent); + } catch (Throwable e) { + e.printStackTrace(); + writeLog(e.toString()); + } + + throwable.printStackTrace(); + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(0); + + } catch (Throwable e) { + if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable); + } + } + + private String buildLog(Throwable throwable) { + String time = DATE_FORMAT.format(new Date()); + + String versionName = "unknown"; + long versionCode = 0; + try { + PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); + versionName = packageInfo.versionName; + versionCode = Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : packageInfo.versionCode; + } catch (Throwable ignored) {} + + LinkedHashMap head = new LinkedHashMap(); + head.put("Time Of Crash", time); + head.put("Device", String.format("%s, %s", Build.MANUFACTURER, Build.MODEL)); + head.put("Android Version", String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT)); + head.put("App Version", String.format("%s (%d)", versionName, versionCode)); + head.put("Kernel", getKernel()); + head.put("Support Abis", Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null ? Arrays.toString(Build.SUPPORTED_ABIS): "unknown"); + head.put("Fingerprint", Build.FINGERPRINT); + + StringBuilder builder = new StringBuilder(); + + for (String key : head.keySet()) { + if (builder.length() != 0) builder.append("\n"); + builder.append(key); + builder.append(" : "); + builder.append(head.get(key)); + } + + builder.append("\n\n"); + builder.append(Log.getStackTraceString(throwable)); + + return builder.toString(); + } + + private void writeLog(String log) { + String time = DATE_FORMAT.format(new Date()); + File file = new File(mCrashDir, "crash_" + time + ".txt"); + try { + write(file, log.getBytes("UTF-8")); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + private static String getKernel() { + try { + return GlobalApplication.toString(new FileInputStream("/proc/version")).trim(); + } catch (Throwable e) { + return e.getMessage(); + } + } + } + } + + public static final class CrashActivity extends Activity { + + private String mLog; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setTheme(android.R.style.Theme_DeviceDefault); + setTitle("App Crash"); + + mLog = getIntent().getStringExtra(Intent.EXTRA_TEXT); + + ScrollView contentView = new ScrollView(this); + contentView.setFillViewport(true); + + HorizontalScrollView horizontalScrollView = new HorizontalScrollView(this); + + TextView textView = new TextView(this); + int padding = dp2px(16); + textView.setPadding(padding, padding, padding, padding); + textView.setText(mLog); + textView.setTextIsSelectable(true); + textView.setTypeface(Typeface.DEFAULT); + textView.setLinksClickable(true); + + horizontalScrollView.addView(textView); + contentView.addView(horizontalScrollView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + + setContentView(contentView); + } + + private void restart() { + Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); + if (intent != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + finish(); + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(0); + } + + private static int dp2px(float dpValue) { + final float scale = Resources.getSystem().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(0, android.R.id.copy, 0, android.R.string.copy) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.copy: + ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog)); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onBackPressed() { + restart(); + } + } +} diff --git a/app/src/main/java/com/bytecat/algui/GradientStrokeDrawable.java b/app/src/main/java/com/bytecat/algui/GradientStrokeDrawable.java new file mode 100644 index 0000000..cc33cce --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/GradientStrokeDrawable.java @@ -0,0 +1,56 @@ +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.graphics.LinearGradient; + +public class GradientStrokeDrawable extends Drawable { + private Paint paint; + private LinearGradient shader; + private int[] colors; + private float strokeWidth; + + public GradientStrokeDrawable(float strokeWidth, int[] colors) { + this.colors = colors; + this.strokeWidth = strokeWidth; + paint = new Paint(); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(strokeWidth); + updateShader(); + } + + private void updateShader() { + shader = new LinearGradient(0, 0, getBounds().width(), 0, + colors, null, Shader.TileMode.CLAMP); + paint.setShader(shader); + } + + @Override + public void draw(Canvas canvas) { + Rect bounds = getBounds(); + canvas.drawRect(bounds, paint); + } + + @Override + public void setAlpha(int alpha) { + paint.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter cf) { + paint.setColorFilter(cf); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + public void setColors(int[] colors) { + this.colors = colors; + updateShader(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/MainActivity.java b/app/src/main/java/com/bytecat/algui/MainActivity.java new file mode 100644 index 0000000..39804b7 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/MainActivity.java @@ -0,0 +1,22 @@ +package com.bytecat.algui; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.FrameLayout; +import com.bytecat.algui.ui.category.SpecialCategoryBox; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.category.Fastesp; +import com.bytecat.algui.ui.category.RemoteLinkWatcher; + +public class MainActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); +//远控 + +Main.start(this); + + + } +} + diff --git a/app/src/main/java/com/bytecat/algui/ace.java b/app/src/main/java/com/bytecat/algui/ace.java new file mode 100644 index 0000000..9f29284 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ace.java @@ -0,0 +1,67 @@ +package com.bytecat.algui; + +import android.content.Context; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.ConcurrentHashMap; +import android.app.Activity; +import java.lang.ref.WeakReference; + +public class ace { + + private static final ConcurrentHashMap runningProcesses = new ConcurrentHashMap<>(); + private static WeakReference contextRef = new WeakReference<>(null); + + + public static void init(Context context) { + contextRef = new WeakReference<>(context.getApplicationContext()); + } + + + public static void executeHiddenBinary(String assetFileName) { + Context context = contextRef.get(); + if (context == null) { + throw new IllegalStateException("Context not initialized. Call ace.init(context) first."); + } + + Process existingProcess = runningProcesses.get(assetFileName); + if (existingProcess != null && existingProcess.isAlive()) { + existingProcess.destroy(); + } + runningProcesses.remove(assetFileName); + + try { + InputStream is = context.getAssets().open(assetFileName); + File tempFile = File.createTempFile("bin_", null, context.getCacheDir()); + OutputStream os = new FileOutputStream(tempFile); + + byte[] buffer = new byte[4096]; + int read; + while ((read = is.read(buffer)) != -1) { + os.write(buffer, 0, read); + } + is.close(); + os.close(); + + Runtime.getRuntime().exec("chmod 777 " + tempFile.getAbsolutePath()).waitFor(); + + Process process = Runtime.getRuntime().exec(tempFile.getAbsolutePath()); + runningProcesses.put(assetFileName, process); + + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } + + public static void stopBinary(String assetFileName) { + Process process = runningProcesses.get(assetFileName); + if (process != null && process.isAlive()) { + process.destroy(); + } + runningProcesses.remove(assetFileName); + } + } + diff --git a/app/src/main/java/com/bytecat/algui/animation/Animated.java b/app/src/main/java/com/bytecat/algui/animation/Animated.java new file mode 100644 index 0000000..234a681 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/animation/Animated.java @@ -0,0 +1,41 @@ +package com.bytecat.algui.animation; + +import android.view.View; + +public class Animated extends BaseAnimated { + + private final android.animation.Animator animator; + + private final View target; + + public Animated(android.animation.Animator animator) { + this(animator, null); + } + + public Animated(android.animation.Animator animator, View target) { + this.animator = animator; + this.target = target; + } + + @Override + public android.animation.Animator build() { + return animator; + } + + @Override + public Animated start() { + if (target != null) { + target.post(new Runnable() { + @Override + public void run() { + Animated.super.start(); + target.removeCallbacks(this); + } + }); + return this; + } else { + return super.start(); + } + } + +} diff --git a/app/src/main/java/com/bytecat/algui/animation/AnimatedSet.java b/app/src/main/java/com/bytecat/algui/animation/AnimatedSet.java new file mode 100644 index 0000000..8e30a04 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/animation/AnimatedSet.java @@ -0,0 +1,38 @@ +package com.bytecat.algui.animation; + +import android.animation.Animator; + +public class AnimatedSet extends BaseAnimated { + + private final android.animation.AnimatorSet animatorSet; + + public AnimatedSet() { + animatorSet = new android.animation.AnimatorSet(); + } + + public AnimatedSet playQueue(BaseAnimated... animators) { + android.animation.AnimatorSet.Builder builder = null; + for (BaseAnimated animator : animators) { + if (builder != null) { + builder.before(animator.build()); + } else { + builder = animatorSet.play(animator.build()); + } + } + return this; + } + + public AnimatedSet playTogether(BaseAnimated... animators) { + final android.animation.Animator[] animatorArray = new Animator[animators.length]; + for (int index = 0; index < animators.length; index++) { + animatorArray[index] = animators[index].build(); + } + animatorSet.playTogether(animatorArray); + return this; + } + + @Override + public android.animation.AnimatorSet build() { + return animatorSet; + } +} diff --git a/app/src/main/java/com/bytecat/algui/animation/BaseAnimated.java b/app/src/main/java/com/bytecat/algui/animation/BaseAnimated.java new file mode 100644 index 0000000..8a2f7e7 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/animation/BaseAnimated.java @@ -0,0 +1,72 @@ +package com.bytecat.algui.animation; + +import android.animation.Animator; +import android.animation.TimeInterpolator; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; + +public abstract class BaseAnimated extends BaseHelper { + + public T setDuration(long duration) { + build().setDuration(duration); + return self(); + } + + public T setStartDelay(long startDelay) { + build().setStartDelay(startDelay); + return self(); + } + + public T setInterpolator(TimeInterpolator interpolator) { + build().setInterpolator(interpolator); + return self(); + } + + public T setTarget(ViewHelper target) { + build().setTarget(target.build()); + return self(); + } + + public T addListener(Animator.AnimatorListener animatorListener) { + build().addListener(animatorListener); + return self(); + } + + public T removeListener(Animator.AnimatorListener animatorListener) { + build().removeListener(animatorListener); + return self(); + } + + public T start() { + build().start(); + return self(); + } + + public T cancel() { + build().cancel(); + return self(); + } + + public T pause() { + build().pause(); + return self(); + } + + public T resume() { + build().resume(); + return self(); + } + + public T end() { + build().end(); + return self(); + } + + public abstract Animator build(); + + private T self() { + return (T) this; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/animation/ObjectAnimated.java b/app/src/main/java/com/bytecat/algui/animation/ObjectAnimated.java new file mode 100644 index 0000000..064bc88 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/animation/ObjectAnimated.java @@ -0,0 +1,93 @@ +package com.bytecat.algui.animation; + +import android.animation.ArgbEvaluator; +import android.view.View; + +import com.bytecat.algui.base.ViewHelper; + +public class ObjectAnimated extends BaseAnimated { + + private final android.animation.ObjectAnimator objectAnimator; + + public ObjectAnimated() { + objectAnimator = new android.animation.ObjectAnimator(); + } + + public ObjectAnimated ofInt(int... values) { + objectAnimator.setIntValues(values); + return this; + } + + public ObjectAnimated ofFloat(float... values) { + objectAnimator.setFloatValues(values); + return this; + } + + public ObjectAnimated ofArgb(int... values) { + objectAnimator.setIntValues(values); + objectAnimator.setEvaluator(new ArgbEvaluator()); + return this; + } + + public ObjectAnimated ofInt(ViewHelper view, String propertyName, int... values) { + objectAnimator.setTarget(view.build()); + objectAnimator.setPropertyName(propertyName); + objectAnimator.setIntValues(values); + return this; + } + + public ObjectAnimated ofFloat(ViewHelper view, String propertyName, float... values) { + objectAnimator.setTarget(view.build()); + objectAnimator.setPropertyName(propertyName); + objectAnimator.setFloatValues(values); + return this; + } + + public ObjectAnimated ofArgb(ViewHelper view, String propertyName, int... values) { + objectAnimator.setTarget(view.build()); + objectAnimator.setPropertyName(propertyName); + objectAnimator.setIntValues(values); + objectAnimator.setEvaluator(new ArgbEvaluator()); + return this; + } + + public ObjectAnimated setAutoCancel(boolean cancel) { + objectAnimator.setAutoCancel(cancel); + return this; + } + + public ObjectAnimated setPropertyName(String propertyName) { + objectAnimator.setPropertyName(propertyName); + return this; + } + + public ObjectAnimated addUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener animatorUpdateListener) { + objectAnimator.addUpdateListener(animatorUpdateListener); + return this; + } + + public ObjectAnimated removeUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener animatorUpdateListener) { + objectAnimator.removeUpdateListener(animatorUpdateListener); + return this; + } + + @Override + public ObjectAnimated start() { + View view = (View) objectAnimator.getTarget(); + if (view != null) { + view.post(new Runnable() { + @Override + public void run() { + ObjectAnimated.super.start(); + } + }); + } + return this; + } + + @Override + public android.animation.ObjectAnimator build() { + return objectAnimator; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/animation/ValueAnimated.java b/app/src/main/java/com/bytecat/algui/animation/ValueAnimated.java new file mode 100644 index 0000000..cf4dc27 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/animation/ValueAnimated.java @@ -0,0 +1,55 @@ +package com.bytecat.algui.animation; + +import android.animation.ArgbEvaluator; +import android.animation.TypeEvaluator; + +public class ValueAnimated extends BaseAnimated { + + private final android.animation.ValueAnimator valueAnimator; + + public ValueAnimated() { + valueAnimator = new android.animation.ValueAnimator(); + } + + public ValueAnimated ofInt(int... values) { + valueAnimator.setIntValues(values); + return this; + } + + public ValueAnimated ofFloat(float... values) { + valueAnimator.setFloatValues(values); + return this; + } + + public ValueAnimated ofArgb(int... values) { + valueAnimator.setIntValues(values); + valueAnimator.setEvaluator(new ArgbEvaluator()); + return this; + } + + public ValueAnimated setRepeatCount(int value) { + valueAnimator.setRepeatCount(value); + return this; + } + + public ValueAnimated setEvaluator(TypeEvaluator evaluator) { + valueAnimator.setEvaluator(evaluator); + return this; + } + + public ValueAnimated addUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener animatorUpdateListener) { + valueAnimator.addUpdateListener(animatorUpdateListener); + return this; + } + + public ValueAnimated removeUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener animatorUpdateListener) { + valueAnimator.removeUpdateListener(animatorUpdateListener); + return this; + } + + @Override + public android.animation.ValueAnimator build() { + return valueAnimator; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/application/AppContext.java b/app/src/main/java/com/bytecat/algui/application/AppContext.java new file mode 100644 index 0000000..61a162d --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/application/AppContext.java @@ -0,0 +1,27 @@ +package com.bytecat.algui.application; + +import android.app.Application; + +import com.bytecat.algui.handler.CrashHandler; +import android.content.Context; + +public class AppContext extends Application { + private static Context context; + + + @Override + public void onCreate() { + super.onCreate(); + CrashHandler.init(getApplicationContext()); + context = getApplicationContext(); + // 初始化 CrashHandler + CrashHandler.init(context); + + } + + public static Context getContext() { + return context; + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/application/AppContext.java.bak b/app/src/main/java/com/bytecat/algui/application/AppContext.java.bak new file mode 100644 index 0000000..8e0f3b3 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/application/AppContext.java.bak @@ -0,0 +1,18 @@ +package com.bytecat.algui.application; + +import android.app.Application; + +import com.bytecat.algui.handler.CrashHandler; + +public class AppContext extends Application { +private static Context context; + + @Override + public void onCreate() { + super.onCreate(); + CrashHandler.init(getApplicationContext()); + context = getApplicationContext(); + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/base/BaseHelper.java b/app/src/main/java/com/bytecat/algui/base/BaseHelper.java new file mode 100644 index 0000000..7d9d256 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/base/BaseHelper.java @@ -0,0 +1,173 @@ +package com.bytecat.algui.base; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Point; +import android.os.Handler; +import android.os.Looper; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.WindowManager; + +import com.bytecat.algui.core.MuCuteUIX; + +public abstract class BaseHelper { + + public static final int MatchParent = -1; + + public static final int WrapContent = -2; + + public static Activity requireActivity() { + return MuCuteUIX.requireActivity(); + } + + public static int W() { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final Point point = new Point(); + windowManager.getDefaultDisplay().getRealSize(point); + return point.x; + } + + public static int H() { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final Point point = new Point(); + windowManager.getDefaultDisplay().getRealSize(point); + return point.y; + } + + public static int SystemW() { + if (isLandscape()) { + return W(); + } + return H(); + } + + public static int SystemH() { + if (isLandscape()) { + return H(); + } + return W(); + } + + public static int MaxSystemWH() { + return Math.max(SystemW(), SystemH()); + } + + public static int MinSystemWH() { + return Math.min(SystemW(), SystemH()); + } + + public static boolean isLandscape() { + return Resources.getSystem().getDisplayMetrics().widthPixels > Resources.getSystem().getDisplayMetrics().heightPixels; + } + + public static void Ui(Runnable runnable) { + MuCuteUIX.checkNotNull(runnable, "runnable"); + requireActivity().runOnUiThread(runnable); + } + + public static void post(Runnable runnable) { + MuCuteUIX.checkNotNull(runnable, "runnable"); + requireActivity().getWindow().getDecorView().post(runnable); + } + + public static void delayed(Runnable runnable, long duration) { + MuCuteUIX.checkNotNull(runnable, "runnable"); + new Handler(Looper.getMainLooper()).postDelayed(runnable, duration); + } + + public static float sp2px(float value) { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + value, + displayMetrics + ); + } + + public static float sp2px(int value) { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + value, + displayMetrics + ); + } + + public static int sp2pxInt(float value) { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + value, + displayMetrics + ); + } + + public static int sp2pxInt(int value) { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + value, + displayMetrics + ); + } + + public static float dip2px(float value) { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + value, + displayMetrics + ); + } + + public static float dip2px(int value) { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + value, + displayMetrics + ); + } + + public static int dip2pxInt(float value) { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + value, + displayMetrics + ); + } + + public static int dip2pxInt(int value) { + final WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + value, + displayMetrics + ); + } + + public static int hexColor(String hex) { + return Color.parseColor(hex); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/base/ViewGroupHelper.java b/app/src/main/java/com/bytecat/algui/base/ViewGroupHelper.java new file mode 100644 index 0000000..45cd510 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/base/ViewGroupHelper.java @@ -0,0 +1,91 @@ +package com.bytecat.algui.base; + +import android.animation.LayoutTransition; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; + +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.interpolator.FastOutSlowInInterpolator; + +import java.util.List; + +public abstract class ViewGroupHelper extends ViewHelper { + + public T addView(List> views) { + final ViewGroup viewGroup = build(); + for (ViewHelper view : views) { + viewGroup.addView(view.build()); + } + return self(); + } + + public T addView(ViewHelper... views) { + final ViewGroup viewGroup = build(); + for (ViewHelper view : views) { + viewGroup.addView(view.build()); + } + return self(); + } + + public T addView(ViewHelper view, int index) { + build().addView(view.build(), index); + return self(); + } + + public T removeView(ViewHelper... views) { + final ViewGroup viewGroup = build(); + for (ViewHelper view : views) { + viewGroup.removeView(view.build()); + } + return self(); + } + + public T removeAllViews() { + final ViewGroup viewGroup = build(); + viewGroup.removeAllViews(); + return self(); + } + + public T removeViewAt(int index) { + build().removeViewAt(index); + return self(); + } + + public T debugContent() { + addView(new Widget()); + return self(); + } + + public T animatedContent() { + return animatedContent(200L); + } + + public T animatedContent(long duration) { + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(duration); + layoutTransition.enableTransitionType(LayoutTransition.CHANGING); + layoutTransition.setInterpolator(LayoutTransition.CHANGING, new FastOutSlowInInterpolator()); + build().setLayoutTransition(layoutTransition); + return self(); + } + + public T clip() { + build().setOutlineProvider(ViewOutlineProvider.BACKGROUND); + build().setClipToOutline(true); + return self(); + } + + public T layoutTransition(long duration) { + LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(duration); + build().setLayoutTransition(layoutTransition); + return self(); + } + + public T layoutTransition() { + return layoutTransition(200L); + } + + public abstract ViewGroup build(); + +} diff --git a/app/src/main/java/com/bytecat/algui/base/ViewHelper.java b/app/src/main/java/com/bytecat/algui/base/ViewHelper.java new file mode 100644 index 0000000..4b2e005 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/base/ViewHelper.java @@ -0,0 +1,215 @@ +package com.bytecat.algui.base; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; + +import com.bytecat.algui.callback.GlobalLayoutCallback; +import com.bytecat.algui.callback.PostCallback; +import com.bytecat.algui.callback.RunCallback; +import com.bytecat.algui.layoutparams.BaseParams; +import com.bytecat.algui.util.GradientDrawableBuilder; + +public abstract class ViewHelper extends BaseHelper { + + public T setId(int id) { + build().setId(id); + return self(); + } + + public T debugBackground() { + setBackground(new ColorDrawable(Color.RED)); + return self(); + } + + public T setBackground(Drawable background) { + build().setBackground(background); + return self(); + } + + public T setBackground(GradientDrawableBuilder background) { + return setBackground(background.build()); + } + + public T setBackgroundColor(int color) { + return setBackground(new ColorDrawable(color)); + } + + public T setTranslationX(float x) { + build().setTranslationX(x); + return self(); + } + + public T setTranslationY(float y) { + build().setTranslationY(y); + return self(); + } + + public T setX(float x) { + build().setX(x); + return self(); + } + + public T setY(float y) { + build().setY(y); + return self(); + } + + public T setAlpha(float alpha) { + build().setAlpha(alpha); + return self(); + } + + public T setPadding(int left, int top, int right, int bottom) { + build().setPadding(left, top, right, bottom); + return self(); + } + + public T setLayoutParams(ViewGroup.LayoutParams layoutParams) { + build().setLayoutParams(layoutParams); + return self(); + } + + public T setLayoutParams(BaseParams layoutParams) { + return setLayoutParams(layoutParams.build()); + } + + public T setOnTouchListener(View.OnTouchListener onTouchListener) { + build().setOnTouchListener(onTouchListener); + return self(); + } + + public T setOnClickListener(View.OnClickListener onClickListener) { + build().setOnClickListener(onClickListener); + return self(); + } + + public T setOnLongClickListener(View.OnLongClickListener onLongClickListener) { + build().setOnLongClickListener(onLongClickListener); + return self(); + } + + public T setFocusable(boolean focusable) { + build().setFocusable(focusable); + return self(); + } + + public T setFocusableInTouchMode(boolean focusableInTouchMode) { + build().setFocusableInTouchMode(focusableInTouchMode); + return self(); + } + + public T setClickable(boolean clickable) { + build().setClickable(clickable); + return self(); + } + + public T setVisibility(int visibility) { + build().setVisibility(visibility); + return self(); + } + + public T setMinWidth(int width) { + build().setMinimumWidth(width); + return self(); + } + + public T setMinHeight(int height) { + build().setMinimumHeight(height); + return self(); + } + + public T setElevation(float elevation) { + build().setElevation(elevation); + return self(); + } + + public T post(final PostCallback postCallback) { + final View view = build(); + view.post(new Runnable() { + @Override + public void run() { + postCallback.onPost(view.getWidth(), view.getHeight()); + } + }); + return self(); + } + + public T postOnce(final PostCallback postCallback) { + final View view = build(); + view.post(new Runnable() { + @Override + public void run() { + postCallback.onPost(view.getWidth(), view.getHeight()); + view.removeCallbacks(this); + } + }); + return self(); + } + + public T postDelayed(final PostCallback postCallback, long duration) { + final View view = build(); + view.postDelayed(new Runnable() { + + @Override + public void run() { + postCallback.onPost(view.getWidth(), view.getHeight()); + } + + }, duration); + return self(); + } + + public T postOnceDelayed(final PostCallback postCallback, long duration) { + final View view = build(); + view.postDelayed(new Runnable() { + + @Override + public void run() { + postCallback.onPost(view.getWidth(), view.getHeight()); + view.removeCallbacks(this); + } + + }, duration); + return self(); + } + + public T globalLayout(final GlobalLayoutCallback globalLayoutCallback) { + final View view = build(); + view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + globalLayoutCallback.onGlobalLayout(view.getWidth(), view.getHeight()); + } + }); + return self(); + } + + public T globalLayoutOnce(final GlobalLayoutCallback globalLayoutCallback) { + final View view = build(); + final ViewTreeObserver viewTreeObserver = view.getViewTreeObserver(); + viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + globalLayoutCallback.onGlobalLayout(view.getWidth(), view.getHeight()); + viewTreeObserver.removeOnGlobalLayoutListener(this); + } + }); + return self(); + } + + public T run(RunCallback runCallback) { + runCallback.onRun(); + return self(); + } + + public abstract View build(); + + protected T self() { + return (T) this; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/ClickCallback.java b/app/src/main/java/com/bytecat/algui/callback/ClickCallback.java new file mode 100644 index 0000000..1457ba3 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/ClickCallback.java @@ -0,0 +1,7 @@ +package com.bytecat.algui.callback; + +public interface ClickCallback { + + void onClick(); + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/DrawCallback.java b/app/src/main/java/com/bytecat/algui/callback/DrawCallback.java new file mode 100644 index 0000000..73b7da0 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/DrawCallback.java @@ -0,0 +1,9 @@ +package com.bytecat.algui.callback; + +import android.graphics.Canvas; + +public interface DrawCallback { + + void onDrawView(Canvas canvas); + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/GlobalLayoutCallback.java b/app/src/main/java/com/bytecat/algui/callback/GlobalLayoutCallback.java new file mode 100644 index 0000000..3e15460 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/GlobalLayoutCallback.java @@ -0,0 +1,7 @@ +package com.bytecat.algui.callback; + +public interface GlobalLayoutCallback { + + void onGlobalLayout(int width, int height); + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/PostCallback.java b/app/src/main/java/com/bytecat/algui/callback/PostCallback.java new file mode 100644 index 0000000..35dba58 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/PostCallback.java @@ -0,0 +1,7 @@ +package com.bytecat.algui.callback; + +public interface PostCallback { + + void onPost(int width, int height); + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/RadioGroupCallback.java b/app/src/main/java/com/bytecat/algui/callback/RadioGroupCallback.java new file mode 100644 index 0000000..7aa1210 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/RadioGroupCallback.java @@ -0,0 +1,7 @@ +package com.bytecat.algui.callback; + +public interface RadioGroupCallback { + + void onChecked(String id); + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/RunCallback.java b/app/src/main/java/com/bytecat/algui/callback/RunCallback.java new file mode 100644 index 0000000..7fea7d5 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/RunCallback.java @@ -0,0 +1,7 @@ +package com.bytecat.algui.callback; + +public interface RunCallback { + + void onRun(); + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/SliderCallback.java b/app/src/main/java/com/bytecat/algui/callback/SliderCallback.java new file mode 100644 index 0000000..dc6305b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/SliderCallback.java @@ -0,0 +1,8 @@ +package com.bytecat.algui.callback; + +public interface SliderCallback { +void onSlide(float newProgress, float oldProgress); + + void onEnabled(boolean isEnabled, float progress); + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/SliderCallback.java.bak b/app/src/main/java/com/bytecat/algui/callback/SliderCallback.java.bak new file mode 100644 index 0000000..44b09c3 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/SliderCallback.java.bak @@ -0,0 +1,9 @@ +package com.bytecat.algui.callback; + +public interface SliderCallback { + + void onSlide(float newProgress, float oldProgress); + + void onEnabled(boolean isEnaabled, float progress); + +} diff --git a/app/src/main/java/com/bytecat/algui/callback/SwitchCallback.java b/app/src/main/java/com/bytecat/algui/callback/SwitchCallback.java new file mode 100644 index 0000000..21c0c0a --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/callback/SwitchCallback.java @@ -0,0 +1,7 @@ +package com.bytecat.algui.callback; + +public interface SwitchCallback { + + boolean onChecked(boolean newState); + +} diff --git a/app/src/main/java/com/bytecat/algui/component/BasicSlider.java b/app/src/main/java/com/bytecat/algui/component/BasicSlider.java new file mode 100644 index 0000000..dc29644 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/BasicSlider.java @@ -0,0 +1,50 @@ +package com.bytecat.algui.component; + +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.view.SliderView; + +public class BasicSlider extends ViewHelper { + + public final SliderView sliderView; + + public BasicSlider() { + sliderView = new SliderView(requireActivity()); + } + + public BasicSlider setMax(float max) { + sliderView.setMax(max); + return this; + } + + public BasicSlider setMin(float min) { + sliderView.setMin(min); + return this; + } + + public BasicSlider setProgress(float progress) { + sliderView.setProgress(progress); + return this; + } + + public BasicSlider setSliderCallback(SliderCallback sliderCallback) { + sliderView.setSliderCallback(sliderCallback); + return this; + } + + public BasicSlider setSliderParams(float max, float min, float progress) { + sliderView.setSliderParams(max, min, progress); + return this; + } + + public BasicSlider setEnabled(boolean isEnabled) { + sliderView.setEnabled1(isEnabled); + return this; + } + + @Override + public SliderView build() { + return sliderView; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/Blur.java b/app/src/main/java/com/bytecat/algui/component/Blur.java new file mode 100644 index 0000000..f91e807 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Blur.java @@ -0,0 +1,29 @@ +package com.bytecat.algui.component; + +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.view.RealtimeBlurView; + +public class Blur extends ViewHelper { + + private final RealtimeBlurView blurView; + + public Blur() { + blurView = new RealtimeBlurView(requireActivity()); + } + + public Blur setBlurRadius(float radius) { + blurView.setBlurRadius(radius); + return this; + } + + public Blur setOverlayColor(int overlayColor) { + blurView.setOverlayColor(overlayColor); + return this; + } + + @Override + public RealtimeBlurView build() { + return blurView; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/Card.java b/app/src/main/java/com/bytecat/algui/component/Card.java new file mode 100644 index 0000000..6b11a24 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Card.java @@ -0,0 +1,34 @@ +package com.bytecat.algui.component; + +import com.bytecat.algui.base.ViewGroupHelper; +import com.bytecat.algui.view.CardView; + +public class Card extends ViewGroupHelper { + + private final CardView cardView; + + public Card() { + cardView = new CardView(requireActivity()); + } + + public Card setRadius(float radius) { + cardView.setRadius(radius); + return this; + } + + public Card setCardElevation(float elevation) { + cardView.setCardElevation(elevation); + return this; + } + + public Card setCardBackgroundColor(int color) { + cardView.setCardBackgroundColor(color); + return this; + } + + @Override + public CardView build() { + return cardView; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/Column.java b/app/src/main/java/com/bytecat/algui/component/Column.java new file mode 100644 index 0000000..5500ee9 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Column.java @@ -0,0 +1,36 @@ +package com.bytecat.algui.component; + +import android.widget.LinearLayout; + +import com.bytecat.algui.base.ViewGroupHelper; + +public class Column extends ViewGroupHelper { + + private final LinearLayout linearLayout; + + public Column() { + linearLayout = new LinearLayout(requireActivity()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + } + + public Column setGravity(int gravity) { + linearLayout.setGravity(gravity); + return this; + } + + public Column setHorizontalGravity(int gravity) { + linearLayout.setHorizontalGravity(gravity); + return this; + } + + public Column setVerticalGravity(int gravity) { + linearLayout.setVerticalGravity(gravity); + return this; + } + + @Override + public LinearLayout build() { + return linearLayout; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/ColumnScroll.java b/app/src/main/java/com/bytecat/algui/component/ColumnScroll.java new file mode 100644 index 0000000..4127698 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/ColumnScroll.java @@ -0,0 +1,62 @@ +package com.bytecat.algui.component; + +import android.widget.ScrollView; + +import com.bytecat.algui.base.ViewGroupHelper; + +public class ColumnScroll extends ViewGroupHelper { + + private final ScrollView scrollView; + + public ColumnScroll() { + scrollView = new ScrollView(requireActivity()); + } + + public ColumnScroll setFillViewport(boolean fillViewport) { + scrollView.setFillViewport(fillViewport); + return this; + } + + public ColumnScroll setScrollBarEnabled(boolean enabled) { + setVerticalScrollBarEnabled(false); + setHorizontalScrollBarEnabled(false); + return this; + } + + public ColumnScroll setVerticalScrollBarEnabled(boolean enabled) { + scrollView.setVerticalScrollBarEnabled(enabled); + return this; + } + + public ColumnScroll setHorizontalScrollBarEnabled(boolean enabled) { + scrollView.setHorizontalScrollBarEnabled(enabled); + return this; + } + + public ColumnScroll setFadingEdgeEnabled(boolean enabled) { + setVerticalFadingEdgeEnabled(enabled); + setHorizontalFadingEdgeEnabled(enabled); + return this; + } + + public ColumnScroll setVerticalFadingEdgeEnabled(boolean enabled) { + scrollView.setVerticalFadingEdgeEnabled(enabled); + return this; + } + + public ColumnScroll setHorizontalFadingEdgeEnabled(boolean enabled) { + scrollView.setHorizontalFadingEdgeEnabled(enabled); + return this; + } + + public ColumnScroll setFadingEdgeLength(int length) { + scrollView.setFadingEdgeLength(length); + return this; + } + + @Override + public ScrollView build() { + return scrollView; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/DrawableView.java b/app/src/main/java/com/bytecat/algui/component/DrawableView.java new file mode 100644 index 0000000..4deffea --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/DrawableView.java @@ -0,0 +1,49 @@ +package com.bytecat.algui.component; + +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.DrawCallback; + +public class DrawableView extends ViewHelper { + + private final com.bytecat.algui.view.DrawableView drawableView; + + public DrawableView() { + drawableView = new com.bytecat.algui.view.DrawableView(requireActivity()); + } + + public DrawableView addDrawCallback(DrawCallback callback) { + build().addDrawCallback(callback); + return this; + } + + public DrawableView removeDrawCallback(DrawCallback callback) { + build().removeDrawCallback(callback); + return this; + } + + public DrawableView invalidate() { + build().invalidate(); + return this; + } + + public DrawableView postInvalidate() { + build().postInvalidate(); + return this; + } + + public DrawableView postInvalidateDelayed(long duration) { + build().postInvalidateDelayed(duration); + return this; + } + + public DrawableView postInvalidateOnAnimation() { + build().postInvalidateOnAnimation(); + return this; + } + + @Override + public com.bytecat.algui.view.DrawableView build() { + return drawableView; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/GradientTextView.java b/app/src/main/java/com/bytecat/algui/component/GradientTextView.java new file mode 100644 index 0000000..565df0e --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/GradientTextView.java @@ -0,0 +1,30 @@ +package com.bytecat.algui.component; + +import android.content.Context; +import android.graphics.*; +import android.widget.TextView; + +public class GradientTextView extends TextView { + + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final LinearGradient gradient = new LinearGradient( + 0, 0, 0, 1, // 垂直 + new int[]{ + Color.RED, Color.YELLOW, Color.GREEN, + Color.CYAN, Color.BLUE, Color.MAGENTA + }, + null, + Shader.TileMode.CLAMP + ); + + public GradientTextView(Context c) { + super(c); + } + + @Override + protected void onDraw(Canvas canvas) { + paint.set(getPaint()); + paint.setShader(gradient); + canvas.drawText(getText().toString(), 0, getBaseline(), paint); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/component/Popup.java b/app/src/main/java/com/bytecat/algui/component/Popup.java new file mode 100644 index 0000000..30c7efb --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Popup.java @@ -0,0 +1,487 @@ +package com.bytecat.algui.component; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.PopupWindow; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.util.GradientDrawableBuilder; + +public class Popup extends BaseHelper { + + private static final boolean IS_FLOATING_MODE = false; + + private final PopupImpl impl; + + public Popup() { + impl = IS_FLOATING_MODE ? new LayoutParamsImpl() : new PopupWindowImpl(); + } + + public boolean isFloatingMode() { + return IS_FLOATING_MODE; + } + + public Popup setWidth(int width) { + impl.setWidth(width); + return this; + } + + public Popup setHeight(int height) { + impl.setHeight(height); + return this; + } + + public Popup setFocusable(boolean focusable) { + impl.setFocusable(focusable); + return this; + } + + public Popup setTouchable(boolean touchable) { + impl.setTouchable(touchable); + return this; + } + + public Popup setAnimation(Animation animation) { + impl.setAnimation(animation); + return this; + } + + public Popup setBackground(Drawable background) { + impl.setBackground(background); + return this; + } + + public Popup setBackground(GradientDrawableBuilder background) { + impl.setBackground(background); + return this; + } + + public Popup setContentView(ViewHelper contentView) { + impl.setContentView(contentView); + return this; + } + + public Popup setGravity(int gravity) { + impl.setGravity(gravity); + return this; + } + + public Popup setElevation(float elevation) { + impl.setElevation(elevation); + return this; + } + + public Popup setPosition(int x, int y) { + impl.setPosition(x, y); + return this; + } + + public Popup show() { + impl.show(); + return this; + } + + public Popup dismiss() { + impl.dismiss(); + return this; + } + + public boolean isShown() { + return impl.isShown(); + } + + public PopupWidget build() { + return impl.getPopupWidget(); + } + + public enum Animation { + Dialog, InputMethod, Toast, Activity, Translucent + } + + private class PopupWindowImpl implements PopupImpl { + + private final PopupWindow popupWindow; + + private final PopupWidget popupWidget; + + private final FrameLayout root; + + @SuppressLint("RtlHardcoded") + private int gravity = Gravity.LEFT | Gravity.TOP; + + private int x; + + private int y; + + public PopupWindowImpl() { + popupWindow = new PopupWindow(); + popupWidget = new PopupWidget(popupWindow); + root = new FrameLayout(requireActivity()); + + popupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); + popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + popupWindow.setBackgroundDrawable(null); + popupWindow.setClippingEnabled(false); + popupWindow.setContentView(root); + } + + @Override + public PopupWidget getPopupWidget() { + return popupWidget; + } + + @Override + public void setWidth(int width) { + popupWindow.setWidth(width); + updateIfNeeded(); + } + + @Override + public void setHeight(int height) { + popupWindow.setHeight(height); + updateIfNeeded(); + } + + @Override + public void setFocusable(boolean focusable) { + popupWindow.setFocusable(focusable); + updateIfNeeded(); + } + + @Override + public void setTouchable(boolean touchable) { + popupWindow.setTouchable(touchable); + updateIfNeeded(); + } + + @Override + public void setAnimation(Animation animation) { + int animationRes = -1; + switch (animation) { + case Dialog: + animationRes = android.R.style.Animation_Dialog; + break; + case InputMethod: + animationRes = android.R.style.Animation_InputMethod; + break; + case Toast: + animationRes = android.R.style.Animation_Toast; + break; + case Activity: + animationRes = android.R.style.Animation_Activity; + break; + case Translucent: + animationRes = android.R.style.Animation_Translucent; + break; + } + popupWindow.setAnimationStyle(animationRes); + updateIfNeeded(); + } + + @Override + public void show() { + if (!popupWindow.isShowing()) { + post(new Runnable() { + @Override + public void run() { + popupWindow.showAtLocation(requireActivity().getWindow().getDecorView(), gravity, x, y); + } + }); + } + } + + @Override + public void dismiss() { + if (popupWindow.isShowing()) { + post(new Runnable() { + @Override + public void run() { + popupWindow.dismiss(); + } + }); + } + } + + @Override + public void setPosition(int x, int y) { + this.x = x; + this.y = y; + updateIfNeeded(); + } + + @Override + public void setGravity(int gravity) { + this.gravity = gravity; + } + + @Override + public void setBackground(Drawable background) { + root.setBackground(background); + } + + @Override + public void setBackground(GradientDrawableBuilder background) { + setBackground(background.build()); + } + + @Override + public void setContentView(ViewHelper contentView) { + root.removeAllViews(); + root.addView(contentView.build()); + } + + @Override + public boolean isShown() { + return popupWindow.isShowing(); + } + + @Override + public void setElevation(float elevation) { + popupWindow.setElevation(elevation); + } + + private void updateIfNeeded() { + post(new Runnable() { + @Override + public void run() { + popupWindow.update(x, y, -1, -1); + } + }); + } + + } + + private class LayoutParamsImpl implements PopupImpl { + + private final WindowManager.LayoutParams layoutParams; + + private final PopupWidget popupWidget; + + private final FrameLayout root; + + private boolean isShown; + + public LayoutParamsImpl() { + layoutParams = new WindowManager.LayoutParams(); + popupWidget = new PopupWidget(layoutParams); + root = new FrameLayout(requireActivity()); + + layoutParams.format = PixelFormat.RGBA_8888; + layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + } else { + layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + } + } + + @Override + public PopupWidget getPopupWidget() { + return popupWidget; + } + + @Override + public void setWidth(int width) { + layoutParams.width = width; + updateIfNeeded(); + } + + @Override + public void setHeight(int height) { + layoutParams.height = height; + updateIfNeeded(); + } + + @Override + public void setFocusable(boolean focusable) { + } + + @Override + public void setTouchable(boolean touchable) { + } + + @Override + public void setAnimation(Animation animation) { + int animationRes = -1; + switch (animation) { + case Dialog: + animationRes = android.R.style.Animation_Dialog; + break; + case InputMethod: + animationRes = android.R.style.Animation_InputMethod; + break; + case Toast: + animationRes = android.R.style.Animation_Toast; + break; + case Activity: + animationRes = android.R.style.Animation_Activity; + break; + case Translucent: + animationRes = android.R.style.Animation_Translucent; + break; + } + layoutParams.windowAnimations = animationRes; + updateIfNeeded(); + } + + @Override + public void show() { + if (!isShown) { + post(new Runnable() { + @Override + public void run() { + try { + WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + windowManager.addView(root, layoutParams); + isShown = true; + } catch (Exception ignored) { + } + } + }); + } + } + + @Override + public void dismiss() { + if (isShown) { + post(new Runnable() { + @Override + public void run() { + try { + WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + windowManager.removeView(root); + isShown = false; + } catch (Exception ignored) { + } + } + }); + } + } + + @Override + public void setPosition(int x, int y) { + layoutParams.x = x; + layoutParams.y = y; + updateIfNeeded(); + } + + @Override + public void setGravity(int gravity) { + layoutParams.gravity = gravity; + updateIfNeeded(); + } + + @Override + public void setBackground(Drawable background) { + root.setBackground(background); + } + + @Override + public void setBackground(GradientDrawableBuilder background) { + setBackground(background.build()); + } + + @Override + public void setContentView(ViewHelper contentView) { + root.removeAllViews(); + root.addView(contentView.build()); + } + + @Override + public boolean isShown() { + return isShown; + } + + @Override + public void setElevation(float elevation) { + + } + + private void updateIfNeeded() { + if (isShown) { + post(new Runnable() { + @Override + public void run() { + try { + WindowManager windowManager = (WindowManager) requireActivity().getSystemService(Context.WINDOW_SERVICE); + windowManager.updateViewLayout(root, layoutParams); + } catch (Exception ignored) { + } + } + }); + } + } + + } + + private interface PopupImpl { + + PopupWidget getPopupWidget(); + + void setWidth(int width); + + void setHeight(int height); + + void setFocusable(boolean focusable); + + void setTouchable(boolean touchable); + + void setAnimation(Animation animation); + + void show(); + + void dismiss(); + + void setPosition(int x, int y); + + void setGravity(int gravity); + + void setBackground(Drawable background); + + void setBackground(GradientDrawableBuilder background); + + void setContentView(ViewHelper contentView); + + boolean isShown(); + + void setElevation(float elevation); + + } + + public static final class PopupWidget { + private PopupWindow popupWindow; + private WindowManager.LayoutParams layoutParams; + + public PopupWidget(PopupWindow popupWindow) { + this.popupWindow = popupWindow; + } + + public PopupWidget(WindowManager.LayoutParams layoutParams) { + this.layoutParams = layoutParams; + } + + public boolean isFloatingMode() { + return layoutParams != null; + } + + public PopupWindow getPopupWindow() { + return popupWindow; + } + + public WindowManager.LayoutParams getLayoutParams() { + return layoutParams; + } + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/Relative.java b/app/src/main/java/com/bytecat/algui/component/Relative.java new file mode 100644 index 0000000..0366282 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Relative.java @@ -0,0 +1,20 @@ +package com.bytecat.algui.component; + +import android.widget.RelativeLayout; + +import com.bytecat.algui.base.ViewGroupHelper; + +public class Relative extends ViewGroupHelper { + + private final RelativeLayout relativeLayout; + + public Relative() { + relativeLayout = new RelativeLayout(requireActivity()); + } + + @Override + public RelativeLayout build() { + return relativeLayout; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/Row.java b/app/src/main/java/com/bytecat/algui/component/Row.java new file mode 100644 index 0000000..015e9a9 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Row.java @@ -0,0 +1,37 @@ +package com.bytecat.algui.component; + +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import com.bytecat.algui.base.ViewGroupHelper; + +public class Row extends ViewGroupHelper { + + private final LinearLayout linearLayout; + + public Row() { + linearLayout = new LinearLayout(requireActivity()); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + } + + public Row setGravity(int gravity) { + linearLayout.setGravity(gravity); + return this; + } + + public Row setHorizontalGravity(int gravity) { + linearLayout.setHorizontalGravity(gravity); + return this; + } + + public Row setVerticalGravity(int gravity) { + linearLayout.setVerticalGravity(gravity); + return this; + } + + @Override + public ViewGroup build() { + return linearLayout; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/RowScroll.java b/app/src/main/java/com/bytecat/algui/component/RowScroll.java new file mode 100644 index 0000000..f719fee --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/RowScroll.java @@ -0,0 +1,62 @@ +package com.bytecat.algui.component; + +import android.widget.HorizontalScrollView; + +import com.bytecat.algui.base.ViewGroupHelper; + +public class RowScroll extends ViewGroupHelper { + + private final HorizontalScrollView horizontalScrollView; + + public RowScroll() { + horizontalScrollView = new HorizontalScrollView(requireActivity()); + } + + public RowScroll setFillViewport(boolean fillViewport) { + horizontalScrollView.setFillViewport(fillViewport); + return this; + } + + public RowScroll setScrollBarEnabled(boolean enabled) { + setVerticalScrollBarEnabled(false); + setHorizontalScrollBarEnabled(false); + return this; + } + + public RowScroll setVerticalScrollBarEnabled(boolean enabled) { + horizontalScrollView.setVerticalScrollBarEnabled(enabled); + return this; + } + + public RowScroll setHorizontalScrollBarEnabled(boolean enabled) { + horizontalScrollView.setHorizontalScrollBarEnabled(enabled); + return this; + } + + public RowScroll setFadingEdgeEnabled(boolean enabled) { + setVerticalFadingEdgeEnabled(enabled); + setHorizontalFadingEdgeEnabled(enabled); + return this; + } + + public RowScroll setVerticalFadingEdgeEnabled(boolean enabled) { + horizontalScrollView.setVerticalFadingEdgeEnabled(enabled); + return this; + } + + public RowScroll setHorizontalFadingEdgeEnabled(boolean enabled) { + horizontalScrollView.setHorizontalFadingEdgeEnabled(enabled); + return this; + } + + public RowScroll setFadingEdgeLength(int length) { + horizontalScrollView.setFadingEdgeLength(length); + return this; + } + + @Override + public HorizontalScrollView build() { + return horizontalScrollView; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/Stack.java b/app/src/main/java/com/bytecat/algui/component/Stack.java new file mode 100644 index 0000000..679dd1b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Stack.java @@ -0,0 +1,20 @@ +package com.bytecat.algui.component; + +import android.widget.FrameLayout; + +import com.bytecat.algui.base.ViewGroupHelper; + +public class Stack extends ViewGroupHelper { + + private final FrameLayout frameLayout; + + public Stack() { + frameLayout = new FrameLayout(requireActivity()); + } + + @Override + public FrameLayout build() { + return frameLayout; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/component/Text.java b/app/src/main/java/com/bytecat/algui/component/Text.java new file mode 100644 index 0000000..93dc884 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Text.java @@ -0,0 +1,112 @@ +package com.bytecat.algui.component; + +import android.graphics.Typeface; +import android.text.Spanned; +import android.text.TextUtils; +import android.widget.TextView; + +import com.bytecat.algui.base.ViewHelper; +import android.content.Context; +import android.graphics.Paint; +import android.graphics.LinearGradient; +import android.graphics.Color; +import android.graphics.Shader; +import android.graphics.Canvas; + +public class Text extends ViewHelper { + + private final TextView textView; + + /* ===== 中英文切换 ===== */ +private String chineseText; +private String englishText; +private String languageSwitchFilePath; + +public Text OText(String chineseText, String englishText) { + this.chineseText = chineseText; + this.englishText = englishText; + updateTextBasedOnFile(); + return this; +} + +public Text setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; +} + +private void updateTextBasedOnFile() { + if (languageSwitchFilePath == null) return; + boolean fileExists = new java.io.File(languageSwitchFilePath).exists(); + String target = fileExists ? chineseText : englishText; + if (target != null) setText(target); +} + + public Text() { + textView = new TextView(requireActivity()); + } + + /* ===== 支持一次性传入中英文的 setText 重载 ===== */ +public Text setText(String chineseText, String englishText) { + return OText(chineseText, englishText); // 复用已有方法 +} + + public Text setText(String text) { + textView.setText(text); + return this; + } + + public Text setText(Spanned text) { + textView.setText(text); + return this; + } + + public Text setTextSize(float textSize) { + textView.setTextSize(textSize); + return this; + } + + public Text setTextIsSelectable(boolean textIsSelectable) { + textView.setTextIsSelectable(textIsSelectable); + return this; + } + + public Text setTextColor(int textColor) { + textView.setTextColor(textColor); + return this; + } + + public Text setTypeface(Typeface typeface) { + textView.setTypeface(typeface); + return this; + } + + public Text setSingleLine(boolean singleLine) { + textView.setSingleLine(singleLine); + if (singleLine) { + textView.setEllipsize(TextUtils.TruncateAt.END); + } + return this; + } + + public Text setGravity(int gravity) { + textView.setGravity(gravity); + return this; + } + + public Text setShadowLayer(float radius, float dx, float fy, int color) { + textView.setShadowLayer(radius, dx, fy, color); + return this; + } + + @Override + public TextView build() { + return textView; + } + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/component/Widget.java b/app/src/main/java/com/bytecat/algui/component/Widget.java new file mode 100644 index 0000000..bbf0a1c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/component/Widget.java @@ -0,0 +1,18 @@ +package com.bytecat.algui.component; + +import com.bytecat.algui.base.ViewHelper; + +public class Widget extends ViewHelper { + + private final android.view.View view; + + public Widget() { + view = new android.view.View(requireActivity()); + } + + @Override + public android.view.View build() { + return view; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/core/MuCuteUIX.java b/app/src/main/java/com/bytecat/algui/core/MuCuteUIX.java new file mode 100644 index 0000000..c87c87a --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/core/MuCuteUIX.java @@ -0,0 +1,36 @@ +package com.bytecat.algui.core; + +import android.app.Activity; + +import java.lang.ref.WeakReference; + +public final class MuCuteUIX { + + private static WeakReference currentMainActivity; + + public static void init(Activity activity) { + if (currentMainActivity != null) { + return; + } + checkNotNull(activity, "activity"); + currentMainActivity = new WeakReference<>(activity); + } + + public static Activity requireActivity() { + if (currentMainActivity == null) { + throw new NullPointerException("currentMainActivity is empty, are you really sure you called the init method?"); + } + Activity activity = currentMainActivity.get(); + if (activity == null) { + throw new NullPointerException("activity was finished, the value is null"); + } + return activity; + } + + public static void checkNotNull(Object target, String name) { + if (target == null) { + throw new NullPointerException(String.format("%s cannot be null", name)); + } + } + +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ArrayList.java b/app/src/main/java/com/bytecat/algui/effect/ArrayList.java new file mode 100644 index 0000000..7b1d0d6 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ArrayList.java @@ -0,0 +1,348 @@ +package com.bytecat.algui.effect; + +import android.animation.LayoutTransition; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.graphics.Typeface; +import android.graphics.drawable.GradientDrawable; +import android.os.SystemClock; +import android.view.Gravity; +import android.view.View; +import android.view.Choreographer; +import android.widget.LinearLayout; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; + +import java.io.File; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.bytecat.algui.ui.MIX; +import android.graphics.Color; + +public class ArrayList extends Popup { + + private static ArrayList instance; + public Activity activity; + protected final Map map = new HashMap<>(); + protected final List items = new java.util.ArrayList<>(); + public Column column; + + private static Item fpsItem; + private static boolean isFpsMonitoring = false; + private static final String fpsItemId = "fps_item"; + + private long lastFrameTime; + private int frameCount; + private float fps; + + @SuppressLint("RtlHardcoded") + public ArrayList() { + setWidth(BaseHelper.MatchParent); + setHeight(BaseHelper.MatchParent); + setFocusable(false); + setTouchable(false); + setGravity(Gravity.RIGHT | Gravity.BOTTOM); + + setContentView(createContentView()); + } + + + @SuppressLint("RtlHardcoded") + private Column createContentView() { + LayoutTransition transition = new LayoutTransition(); + transition.setDuration(200L); + + column = new Column().setGravity(Gravity.RIGHT); + column.build().setLayoutTransition(transition); + column.setPadding(0, 10, 10, 0); // 具体 padding 由 DynamicArrayList 再设 + + // 新增:把 ArrayListView 挂到 column 的右下角 + final ArrayListView moduleListView = new ArrayListView(MIX.getContext()); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.END | Gravity.BOTTOM; + moduleListView.setLayoutParams(lp); + column.build().addView(moduleListView); + // 创建颜色选择器小容器并追加 + + return column; + } + + public static void showFpsDisplay() { + if (!isFpsMonitoring) { + getInstance().addFpsDisplay(); + isFpsMonitoring = true; + } + } + + public static void hideFpsDisplay() { + if (isFpsMonitoring) { + getInstance().removeFpsDisplay(); + isFpsMonitoring = false; + } + } + + private void addFpsDisplay() { + if (!map.containsKey(fpsItemId)) { + fpsItem = new Item(MIX.getContext(), "FPS: 0", fpsItemId); + map.put(fpsItemId, fpsItem); + addItem(fpsItem); + } + startFpsMonitoring(); + } + + private void removeFpsDisplay() { + if (map.containsKey(fpsItemId)) { + Item item = map.remove(fpsItemId); + removeItem(item); + } + } + + private void startFpsMonitoring() { + lastFrameTime = SystemClock.uptimeMillis(); + frameCount = 0; + fps = 0.0f; + + Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() { + @Override + public void doFrame(long frameTimeNanos) { + long current = SystemClock.uptimeMillis(); + frameCount++; + if (current - lastFrameTime >= 1000) { + fps = frameCount / ((current - lastFrameTime) / 1000.0f); + lastFrameTime = current; + frameCount = 0; + if (fpsItem != null) fpsItem.setTitle("FPS: " + String.format("%.1f", fps)); + } + Choreographer.getInstance().postFrameCallback(this); + } + }); + } + + public ArrayList showArrayList() { + column.build().animate() + .alpha(1f) + .setDuration(200L) + .withStartAction(new Runnable() { + @Override + public void run() { + column.setVisibility(View.VISIBLE); + } + }) + .start(); + return this; + } + + public ArrayList hideArrayList() { + column.build().animate() + .alpha(0f) + .setDuration(200L) + .withEndAction(new Runnable() { + @Override + public void run() { + column.setVisibility(View.GONE); + } + }) + .start(); + return this; + } + + public ArrayList addArrayList(String title, String id) { + return addArrayList(title, id, title); + } + + public ArrayList addArrayList(String chineseTitle, String id, String englishTitle) { + if (!map.containsKey(id)) { + String langPath = "/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; + String display = new File(langPath).exists() ? chineseTitle : englishTitle; + Item item = new Item(MIX.getContext(), display, id); + map.put(id, item); + addItem(item); + } + return this; + } + + public ArrayList removeArrayList(String id) { + Item item = map.remove(id); + if (item != null) removeItem(item); + return this; + } + + private void addItem(final Item item) { + items.add(item); + sort(); + int index = items.indexOf(item); + if (index >= 0) { + column.build().addView(item, index); + } + } + + private void removeItem(final Item item) { + int index = items.indexOf(item); + if (index >= 0) { + items.remove(index); + column.build().removeView(item); // ✅ 直接移除,触发平移动画 + + } + + } + + // ArrayList.java + protected void onItemCountChanged() { + // 子类可重写 + } + + + private void sort() { + Collections.sort(items, new Comparator() { + @Override + public int compare(Item a, Item b) { + float widthA = a.textView.build().getPaint().measureText(b.title); + float widthB = b.textView.build().getPaint().measureText(a.title); + return (int) (widthA - widthB); + } + }); + } + + public static ArrayList getInstance() { + if (instance == null) instance = new ArrayList(); + return instance; + } + + // ✅ 新的 Item:LinearLayout + Text + 红线 + public static class Item extends LinearLayout { + private final Text textView; + private String title; + private String id; + // 在 Item 类里新增字段 + private View stripeView; + +// 在构造函数里保存引用(只贴关键) + + +// 新增公开方法 + + + @SuppressLint("RtlHardcoded") + public Item(Context context, String title, String id) { + super(context); + this.title = title; + this.id = id; + + // ✅ 宽度随内容 + setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + // ✅ 最外层布局 + setOrientation(HORIZONTAL); + setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL); + setPadding( + BaseHelper.dip2pxInt(7), + BaseHelper.dip2pxInt(2), + BaseHelper.dip2pxInt(7), + BaseHelper.dip2pxInt(2) + ); + +// ✅ 文本背景容器 + textView = new Text(); + textView.setTextColor(BaseHelper.hexColor("#FF999999")); + textView.setTextSize(12f); + textView.setTypeface(Typeface.DEFAULT_BOLD); + textView.setText(title); + textView.setGravity(Gravity.CENTER_VERTICAL); + textView.setPadding( + BaseHelper.dip2pxInt(7), + BaseHelper.dip2pxInt(3), + BaseHelper.dip2pxInt(7), + BaseHelper.dip2pxInt(3) + ); + + +// ✅ 设置文本背景 + + +// ✅ 条纹(独立竖线) + + stripeView = new View(context); + GradientDrawable stripeBg = new GradientDrawable(); + stripeBg.setColor(Color.RED); + float r = BaseHelper.dip2px(3); // 圆角半径 + stripeBg.setCornerRadii(new float[]{ + 0, 0, // 左上 + r, r, // 右上 + r, r, // 右下 + 0, 0 // 左下 + }); + + stripeView.setBackground(stripeBg); + + int stripeWidth = BaseHelper.dip2pxInt(3); + LayoutParams stripeParams = new LayoutParams( + stripeWidth, + LayoutParams.MATCH_PARENT // 与文本背景同高 + ); + + stripeParams.setMargins(0, 0, 0, 0); // 左侧留空 + stripeView.setLayoutParams(stripeParams); + + GradientDrawable textBg = new GradientDrawable(); + textBg.setColor(BaseHelper.hexColor("#B32C2C32")); + textBg.setCornerRadii(new float[]{ + r, r, // 左上 + 0, 0, // 右上 + 0, 0, // 右下 + r, r // 左下 + }); + textView.build().setBackground(textBg); + +// ✅ 添加顺序:先文本,后条纹 + addView(textView.build()); + addView(stripeView); + + } + + + + + // 在 ArrayList.Item 里 + public void setTextColor(int color) { + textView.setTextColor(color); + } + + public void setStripeColor(int color) { + ((GradientDrawable) stripeView.getBackground()).setColor(color); + } + + public Item setTitle(String title) { + this.title = title; + textView.setText(title); + return this; + } + + public Item setId(String id) { + this.id = id; + return this; + } + + public String getTitle() { + return title; + } + + public String getItemId() { + return id; + } + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ArrayList.java.bak b/app/src/main/java/com/bytecat/algui/effect/ArrayList.java.bak new file mode 100644 index 0000000..1f528c3 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ArrayList.java.bak @@ -0,0 +1,348 @@ +package com.bytecat.algui.effect; + +import android.animation.LayoutTransition; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.graphics.Typeface; +import android.graphics.drawable.GradientDrawable; +import android.os.SystemClock; +import android.view.Gravity; +import android.view.View; +import android.view.Choreographer; +import android.widget.LinearLayout; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; + +import java.io.File; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.bytecat.algui.ui.MIX; +import android.graphics.Color; + +public class ArrayList extends Popup { + + private static ArrayList instance; + public Activity activity; + protected final Map map = new HashMap<>(); + protected final List items = new java.util.ArrayList<>(); + public Column column; + + private static Item fpsItem; + private static boolean isFpsMonitoring = false; + private static final String fpsItemId = "fps_item"; + + private long lastFrameTime; + private int frameCount; + private float fps; + + @SuppressLint("RtlHardcoded") + public ArrayList() { + setWidth(BaseHelper.MatchParent); + setHeight(BaseHelper.MatchParent); + setFocusable(false); + setTouchable(false); + setGravity(Gravity.RIGHT | Gravity.BOTTOM); + + setContentView(createContentView()); + } + + + @SuppressLint("RtlHardcoded") + private Column createContentView() { + LayoutTransition transition = new LayoutTransition(); + transition.setDuration(200L); + + column = new Column().setGravity(Gravity.RIGHT); + column.build().setLayoutTransition(transition); + column.setPadding(0, 10, 10, 0); // 具体 padding 由 DynamicArrayList 再设 + + // 新增:把 ArrayListView 挂到 column 的右下角 + final ArrayListView moduleListView = new ArrayListView(MIX.getContext()); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.END | Gravity.BOTTOM; + moduleListView.setLayoutParams(lp); + column.build().addView(moduleListView); + // 创建颜色选择器小容器并追加 + + return column; + } + + public static void showFpsDisplay() { + if (!isFpsMonitoring) { + getInstance().addFpsDisplay(); + isFpsMonitoring = true; + } + } + + public static void hideFpsDisplay() { + if (isFpsMonitoring) { + getInstance().removeFpsDisplay(); + isFpsMonitoring = false; + } + } + + private void addFpsDisplay() { + if (!map.containsKey(fpsItemId)) { + fpsItem = new Item(MIX.getContext(), "FPS: 0", fpsItemId); + map.put(fpsItemId, fpsItem); + addItem(fpsItem); + } + startFpsMonitoring(); + } + + private void removeFpsDisplay() { + if (map.containsKey(fpsItemId)) { + Item item = map.remove(fpsItemId); + removeItem(item); + } + } + + private void startFpsMonitoring() { + lastFrameTime = SystemClock.uptimeMillis(); + frameCount = 0; + fps = 0.0f; + + Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() { + @Override + public void doFrame(long frameTimeNanos) { + long current = SystemClock.uptimeMillis(); + frameCount++; + if (current - lastFrameTime >= 1000) { + fps = frameCount / ((current - lastFrameTime) / 1000.0f); + lastFrameTime = current; + frameCount = 0; + if (fpsItem != null) fpsItem.setTitle("FPS: " + String.format("%.1f", fps)); + } + Choreographer.getInstance().postFrameCallback(this); + } + }); + } + + public ArrayList showArrayList() { + column.build().animate() + .alpha(1f) + .setDuration(200L) + .withStartAction(new Runnable() { + @Override + public void run() { + column.setVisibility(View.VISIBLE); + } + }) + .start(); + return this; + } + + public ArrayList hideArrayList() { + column.build().animate() + .alpha(0f) + .setDuration(200L) + .withEndAction(new Runnable() { + @Override + public void run() { + column.setVisibility(View.GONE); + } + }) + .start(); + return this; + } + + public ArrayList addArrayList(String title, String id) { + return addArrayList(title, id, title); + } + + public ArrayList addArrayList(String chineseTitle, String id, String englishTitle) { + if (!map.containsKey(id)) { + String langPath = "/sdcard/TC配置文件/switch.lang"; + String display = new File(langPath).exists() ? chineseTitle : englishTitle; + Item item = new Item(MIX.getContext(), display, id); + map.put(id, item); + addItem(item); + } + return this; + } + + public ArrayList removeArrayList(String id) { + Item item = map.remove(id); + if (item != null) removeItem(item); + return this; + } + + private void addItem(final Item item) { + items.add(item); + sort(); + int index = items.indexOf(item); + if (index >= 0) { + column.build().addView(item, index); + } + } + + private void removeItem(final Item item) { + int index = items.indexOf(item); + if (index >= 0) { + items.remove(index); + column.build().removeView(item); // ✅ 直接移除,触发平移动画 + + } + + } + + // ArrayList.java + protected void onItemCountChanged() { + // 子类可重写 + } + + + private void sort() { + Collections.sort(items, new Comparator() { + @Override + public int compare(Item a, Item b) { + float widthA = a.textView.build().getPaint().measureText(b.title); + float widthB = b.textView.build().getPaint().measureText(a.title); + return (int) (widthA - widthB); + } + }); + } + + public static ArrayList getInstance() { + if (instance == null) instance = new ArrayList(); + return instance; + } + + // ✅ 新的 Item:LinearLayout + Text + 红线 + public static class Item extends LinearLayout { + private final Text textView; + private String title; + private String id; + // 在 Item 类里新增字段 + private View stripeView; + +// 在构造函数里保存引用(只贴关键) + + +// 新增公开方法 + + + @SuppressLint("RtlHardcoded") + public Item(Context context, String title, String id) { + super(context); + this.title = title; + this.id = id; + + // ✅ 宽度随内容 + setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + // ✅ 最外层布局 + setOrientation(HORIZONTAL); + setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL); + setPadding( + BaseHelper.dip2pxInt(7), + BaseHelper.dip2pxInt(2), + BaseHelper.dip2pxInt(7), + BaseHelper.dip2pxInt(2) + ); + +// ✅ 文本背景容器 + textView = new Text(); + textView.setTextColor(BaseHelper.hexColor("#FF999999")); + textView.setTextSize(12f); + textView.setTypeface(Typeface.DEFAULT_BOLD); + textView.setText(title); + textView.setGravity(Gravity.CENTER_VERTICAL); + textView.setPadding( + BaseHelper.dip2pxInt(7), + BaseHelper.dip2pxInt(3), + BaseHelper.dip2pxInt(7), + BaseHelper.dip2pxInt(3) + ); + + +// ✅ 设置文本背景 + + +// ✅ 条纹(独立竖线) + + stripeView = new View(context); + GradientDrawable stripeBg = new GradientDrawable(); + stripeBg.setColor(Color.RED); + float r = BaseHelper.dip2px(3); // 圆角半径 + stripeBg.setCornerRadii(new float[]{ + 0, 0, // 左上 + r, r, // 右上 + r, r, // 右下 + 0, 0 // 左下 + }); + + stripeView.setBackground(stripeBg); + + int stripeWidth = BaseHelper.dip2pxInt(3); + LayoutParams stripeParams = new LayoutParams( + stripeWidth, + LayoutParams.MATCH_PARENT // 与文本背景同高 + ); + + stripeParams.setMargins(0, 0, 0, 0); // 左侧留空 + stripeView.setLayoutParams(stripeParams); + + GradientDrawable textBg = new GradientDrawable(); + textBg.setColor(BaseHelper.hexColor("#B32C2C32")); + textBg.setCornerRadii(new float[]{ + r, r, // 左上 + 0, 0, // 右上 + 0, 0, // 右下 + r, r // 左下 + }); + textView.build().setBackground(textBg); + +// ✅ 添加顺序:先文本,后条纹 + addView(textView.build()); + addView(stripeView); + + } + + + + + // 在 ArrayList.Item 里 + public void setTextColor(int color) { + textView.setTextColor(color); + } + + public void setStripeColor(int color) { + ((GradientDrawable) stripeView.getBackground()).setColor(color); + } + + public Item setTitle(String title) { + this.title = title; + textView.setText(title); + return this; + } + + public Item setId(String id) { + this.id = id; + return this; + } + + public String getTitle() { + return title; + } + + public String getItemId() { + return id; + } + } + + +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ArrayListView.java b/app/src/main/java/com/bytecat/algui/effect/ArrayListView.java new file mode 100644 index 0000000..e67b7e9 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ArrayListView.java @@ -0,0 +1,739 @@ +// ========= 第一段:类头、成员变量、接口实现 ========= +package com.bytecat.algui.effect; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.LayoutTransition; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.*; +import android.view.*; +import android.widget.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import android.content.res.Resources; +import android.view.animation.*; +import android.animation.*; +import android.graphics.drawable.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import androidx.annotation.*; +import android.text.style.*; +import android.text.*; + + +public class ArrayListView extends LinearLayout implements ThemeManager.OnThemeColorChangeListener { + + private final Map moduleViews = new ConcurrentHashMap(); + private int mStaticColor = ThemeManager.getInstance().getThemeColor(); + private static boolean sGlowEnabled = true; + private final Paint glowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private static ArrayListView sInstance; + private static boolean sDynamicGradient = true; + private static int sBgAlpha = 255; + + private final List activeModules = Collections.synchronizedList(new ArrayList()); + private ValueAnimator rainbowAnimator; + private final Paint borderPaint = new Paint(); + private final Map animationStates = new ConcurrentHashMap(); + + + private enum ModuleStatus { ADDING, ACTIVE, REMOVING } + private final Map moduleStatuses = new ConcurrentHashMap(); + + private static class BorderAnimationState { + ValueAnimator animator; + float progress = 0f; + float connectionStartX; + float connectionProgress = 1f; + final ArrayListView parent; + BorderAnimationState(ArrayListView parent) { this.parent = parent; } + + void animate(boolean appearing, final Runnable onEndAction) { + if (animator != null && animator.isRunning()) animator.cancel(); + float start = appearing ? progress : 1f; + float end = appearing ? 1f : 0f; + animator = ValueAnimator.ofFloat(start, end); + animator.setDuration(300); + animator.setInterpolator(new SmoothInterpolator()); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + progress = (Float) animation.getAnimatedValue(); + parent.invalidate(); + } + }); + if (onEndAction != null) { + animator.addListener(new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { onEndAction.run(); } + }); + } + animator.start(); + } + + void animateConnection(float startX) { + this.connectionStartX = startX; + ValueAnimator connAnimator = ValueAnimator.ofFloat(0f, 1f); + connAnimator.setDuration(300); + connAnimator.setInterpolator(new SmoothInterpolator()); + connAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + connectionProgress = (Float) animation.getAnimatedValue(); + parent.invalidate(); + } + }); + connAnimator.start(); + } + } + + public ArrayListView(Context context) { + super(context); + setOrientation(LinearLayout.VERTICAL); + setGravity(Gravity.END); + setClipChildren(false); + setClipToPadding(false); + + borderPaint.setStyle(Paint.Style.STROKE); + borderPaint.setAntiAlias(true); + borderPaint.setStrokeWidth(dpToPx(1.5f)); + + LayoutTransition lt = new LayoutTransition(); + lt.setStagger(LayoutTransition.CHANGING, 30); + lt.setDuration(300); + lt.disableTransitionType(LayoutTransition.APPEARING); + lt.disableTransitionType(LayoutTransition.DISAPPEARING); + setLayoutTransition(lt); + + sInstance = this; + + ModuleManager.getInstance().addOnModuleAddedListener(new ModuleManager.ModuleListener() { + @Override + public void onEvent(String moduleName) { + addModule(moduleName); + } + }); + + ModuleManager.getInstance().addOnModuleRemovedListener(new ModuleManager.ModuleListener() { + @Override + public void onEvent(String moduleName) { + removeModule(moduleName); + } + }); + + ModuleManager.getInstance().addOnNotificationListener(new ModuleManager.ModuleListener() { + @Override + public void onEvent(String moduleName) { + refreshModuleSubtitle(moduleName); + } + }); + ModuleManager.getInstance().addOnNotificationListener(new ModuleManager.ModuleListener() { + public void onEvent(String moduleName) { + refreshModuleSubtitle(moduleName); + refreshModuleTitle(moduleName); // 新增 + } + }); + + ThemeManager.getInstance().addListener(this); + } + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + synchronized (activeModules) { + for (int i = 0; i < activeModules.size(); i++) { + String moduleName = activeModules.get(i); + if (moduleStatuses.get(moduleName) == ModuleStatus.REMOVING) continue; + + LinearLayout currentContainer = moduleViews.get(moduleName); + TextView mainTextView = findMainTextView(currentContainer); + BorderAnimationState state = animationStates.get(moduleName); + + if (currentContainer == null || mainTextView == null || state == null) continue; + + int currentColor = mainTextView.getCurrentTextColor(); + + // 找到下一个可见模块颜色 + TextView nextMainTextView = null; + for (int j = i + 1; j < activeModules.size(); j++) { + String nextModuleName = activeModules.get(j); + if (moduleStatuses.get(nextModuleName) != ModuleStatus.REMOVING) { + nextMainTextView = findMainTextView(moduleViews.get(nextModuleName)); + break; + } + } + int nextColor = (nextMainTextView != null) + ? nextMainTextView.getCurrentTextColor() + : currentColor; + + // 为当前文字设置上下渐变(当前 -> 下一模块颜色) + applyTextGradient(mainTextView, currentColor, nextColor); + + // —— 以下边框绘制逻辑不变 —— + float left = currentContainer.getLeft() + currentContainer.getTranslationX(); + float top = currentContainer.getTop(); + float right = currentContainer.getRight() + currentContainer.getTranslationX(); + float bottom = currentContainer.getBottom(); + + LinearLayout nextContainer = null; + for (int j = i + 1; j < activeModules.size(); j++) { + String nextModuleName = activeModules.get(j); + if (moduleStatuses.get(nextModuleName) != ModuleStatus.REMOVING) { + nextContainer = moduleViews.get(nextModuleName); + break; + } + } + + // 上边框 + if (i == 0) { + setShader(borderPaint, null); + borderPaint.setColor(currentColor); + canvas.drawLine(left, top, + left + (right - left) * state.progress, top, borderPaint); + } + + // 左边框(垂直渐变) + LinearGradient verticalGradient = new LinearGradient( + left, top, left, bottom, + new int[]{currentColor, nextColor}, + new float[]{0f, 1f}, + Shader.TileMode.CLAMP); + setShader(borderPaint, verticalGradient); + canvas.drawLine(left, top, + left, top + (bottom - top) * state.progress, borderPaint); + + // 连接线 / 下边框 + if (nextContainer != null) { + float nextLeft = nextContainer.getLeft() + nextContainer.getTranslationX(); + float targetX = nextLeft; + if (state.connectionProgress < 1f) { + targetX = state.connectionStartX + + (nextLeft - state.connectionStartX) * state.connectionProgress; + } + LinearGradient horizontalGradient = new LinearGradient( + left, bottom, targetX, bottom, + new int[]{nextColor, nextColor}, + new float[]{0f, 1f}, + Shader.TileMode.CLAMP); + setShader(borderPaint, horizontalGradient); + canvas.drawLine(left, bottom, + left + (targetX - left) * state.progress, bottom, borderPaint); + } else { + setShader(borderPaint, null); + borderPaint.setColor(currentColor); + canvas.drawLine(left, bottom, + left + (right - left) * state.progress, bottom, borderPaint); + } + } + setShader(borderPaint, null); + } + } + + private void setShader(Paint paint, Shader shader) { + paint.setShader(shader); + if (sGlowEnabled) { + glowPaint.set(paint); // 同步发光画笔 + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int extraW = (int) dpToPx(60); + int extraH = (int) dpToPx(25); + setMeasuredDimension(getMeasuredWidth() + extraW, getMeasuredHeight() + extraH); + } + + private void refreshModuleSubtitle(final String moduleName) { + post(new Runnable() { + public void run() { + LinearLayout row = moduleViews.get(moduleName); + if (row == null) return; + TextView sub = (TextView) row.findViewWithTag("sub"); + if (sub != null) { + sub.setText(ModuleManager.getInstance().getModuleSubtitle(moduleName)); + sortModulesByWidth(); + } + } + }); + } + + private void refreshModuleTitle(final String moduleName) { + post(new Runnable() { + public void run() { + LinearLayout row = moduleViews.get(moduleName); + if (row == null) return; + TextView main = (TextView) row.findViewWithTag("main"); + if (main != null) { + main.setText(ModuleManager.getInstance().getModuleTitle(moduleName)); + sortModulesByWidth(); // 宽度可能变化,重新排序 + } + } + }); + } + + private void addModule(final String moduleName) { + if (moduleStatuses.get(moduleName) == ModuleStatus.REMOVING) { + moduleStatuses.put(moduleName, ModuleStatus.ACTIVE); + final LinearLayout moduleText = moduleViews.get(moduleName); + final BorderAnimationState state = animationStates.get(moduleName); + if (moduleText != null && state != null) { + post(new Runnable() { + public void run() { + moduleText.animate().cancel(); + state.animate(true, null); + moduleText.animate().alpha(1f).scaleX(1f).scaleY(1f).translationX(0f).setDuration(300).start(); + } + }); + } + return; + } + if (moduleStatuses.containsKey(moduleName)) return; + + moduleStatuses.put(moduleName, ModuleStatus.ADDING); + final LinearLayout moduleLayout = createModuleLayout(moduleName); + moduleViews.put(moduleName, moduleLayout); + + int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + moduleLayout.measure(spec, spec); + final int newModuleWidth = moduleLayout.getMeasuredWidth(); + final BorderAnimationState state = new BorderAnimationState(this); + animationStates.put(moduleName, state); + + post(new Runnable() { + public void run() { + int newIndex = 0; + synchronized (activeModules) { + for (String existingModuleName : activeModules) { + if (moduleStatuses.get(existingModuleName) == ModuleStatus.REMOVING) continue; + View existingView = moduleViews.get(existingModuleName); + if (existingView != null && newModuleWidth > existingView.getMeasuredWidth()) { + break; + } + newIndex++; + } + } + + if (newIndex > activeModules.size()) newIndex = activeModules.size(); + activeModules.add(newIndex, moduleName); + addView(moduleLayout, newIndex); + + final Runnable endAction = new Runnable() { + public void run() { + moduleStatuses.put(moduleName, ModuleStatus.ACTIVE); + } + }; + TimeInterpolator fastInSlowEnd = new TimeInterpolator() { + public float getInterpolation(float input) { + return 1f - (1f - input) * (1f - input); + } + }; + + moduleLayout.setAlpha(0f); + moduleLayout.setTranslationX(getWidth()); + moduleLayout.animate() + .alpha(1f) + .translationX(0f) + .setDuration(1000) // 更短更优雅 + .setInterpolator(new SmoothInterpolator()) + .withEndAction(endAction) + .start(); + + state.animate(true, null); + } + }); + } + + private void removeModule(final String moduleName) { + if (!moduleStatuses.containsKey(moduleName) || moduleStatuses.get(moduleName) == ModuleStatus.REMOVING) { + return; + } + moduleStatuses.put(moduleName, ModuleStatus.REMOVING); + final LinearLayout moduleText = moduleViews.get(moduleName); + final BorderAnimationState state = animationStates.get(moduleName); + if (moduleText == null || state == null) return; + + + + final int currentIndex = activeModules.indexOf(moduleName); + if (currentIndex > 0) { + for (int i = currentIndex - 1; i >= 0; i--) { + String prevModuleName = activeModules.get(i); + if (moduleStatuses.get(prevModuleName) != ModuleStatus.REMOVING) { + BorderAnimationState prevState = animationStates.get(prevModuleName); + if (prevState != null) prevState.animateConnection(moduleText.getLeft()); + break; + } + } + } + + final Runnable endAction = new Runnable() { + public void run() { + moduleStatuses.remove(moduleName); // 彻底移除状态 + moduleViews.remove(moduleName); + animationStates.remove(moduleName); + activeModules.remove(moduleName); + removeView(moduleText); + + } + }; + + post(new Runnable() { + public void run() { + moduleText.animate() + .alpha(0f) + .translationX(moduleText.getWidth()) + .setDuration(800) + .setInterpolator(new SmoothInterpolator()) + .withEndAction(endAction) + .start(); + } + }); + } + + private void sortModulesByWidth() { + synchronized (activeModules) { + List viewDataList = (List) new ArrayList(); + for (String moduleName : activeModules) { + if (moduleStatuses.get(moduleName) != ModuleStatus.REMOVING) { + viewDataList.add(new ViewData(moduleName, moduleViews.get(moduleName))); + } + } + + Collections.sort(viewDataList, new Comparator() { + public int compare(ViewData o1, ViewData o2) { + return o2.view.getMeasuredWidth() - o1.view.getMeasuredWidth(); + } + }); + + activeModules.clear(); + for (ViewData data : viewDataList) { + activeModules.add(data.name); + data.view.bringToFront(); + } + } + requestLayout(); + invalidate(); + } + + private static class ViewData { + String name; + View view; + ViewData(String name, View view) { + this.name = name; + this.view = view; + } + } + + private LinearLayout createModuleLayout(final String moduleName) { + Context ctx = getContext(); + LinearLayout row = new LinearLayout(ctx); + row.setOrientation(LinearLayout.HORIZONTAL); + row.setGravity(Gravity.END | Gravity.BOTTOM); + row.setBackgroundColor(Color.parseColor("#80FFFFFF")); + row.setPadding((int) dpToPx(4), 0, (int) dpToPx(4), 0); + + int h = (int) dpToPx(16); + + TextView main = new TextView(ctx); + main.setTag("main"); + main.setText(ModuleManager.getInstance().getModuleTitle(moduleName)); + main.setTextSize(13); + main.setTextColor(Color.WHITE); + main.setGravity(Gravity.BOTTOM | Gravity.END); + + + LinearLayout.LayoutParams lpMain = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, h); + lpMain.gravity = Gravity.BOTTOM | Gravity.END; + main.setLayoutParams(lpMain); + + + TextView sub = new TextView(ctx); + sub.setTag("sub"); + sub.setText(ModuleManager.getInstance().getModuleSubtitle(moduleName)); + sub.setTextSize(13); + sub.setTextColor(Color.parseColor("#85000000")); + sub.setGravity(Gravity.BOTTOM | Gravity.END); + sub.setMinHeight(h); + try { + Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/TrosCore.ttf"); + sub.setTypeface(tf); + } catch (Exception e) { + // ignore + } + LinearLayout.LayoutParams lpSub = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + lpSub.gravity = Gravity.BOTTOM | Gravity.END; + lpSub.leftMargin = (int) dpToPx(2); + sub.setLayoutParams(lpSub); + + row.addView(main); + row.addView(sub); + + LinearLayout.LayoutParams rowLp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + row.setLayoutParams(rowLp); + return row; + } + + private TextView findMainTextView(LinearLayout container) { + if (container == null) return null; + return (TextView) container.findViewWithTag("main"); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + startRainbowAnimation(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + stopRainbowAnimation(); + } + + public static void setDynamicGradient(boolean enable) { + if (sInstance == null) return; + sDynamicGradient = enable; + if (enable) sInstance.startRainbowAnimation(); + else sInstance.stopRainbowAnimation(); + } + + private void startRainbowAnimation() { + if (rainbowAnimator != null && rainbowAnimator.isRunning()) return; + rainbowAnimator = ValueAnimator.ofFloat(0f, 360f); + rainbowAnimator.setDuration(3000); + rainbowAnimator.setRepeatCount(ValueAnimator.INFINITE); + rainbowAnimator.setInterpolator(new SmoothInterpolator()); + rainbowAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + if (!sDynamicGradient) return; + applyRainbowColors((Float) animation.getAnimatedValue()); + invalidate(); + } + }); + rainbowAnimator.start(); + } + + private void stopRainbowAnimation() { + if (rainbowAnimator != null) { + rainbowAnimator.cancel(); + rainbowAnimator = null; + } + } + + private void applyTextGradient(final TextView tv, final int topColor, final int bottomColor) { + tv.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + tv.getViewTreeObserver().removeOnPreDrawListener(this); + + LinearGradient gradient = new LinearGradient( + 0, 0, 0, tv.getHeight(), + topColor, bottomColor, + Shader.TileMode.CLAMP + ); + tv.getPaint().setShader(gradient); + // 用 SRC_IN 只在文字区域绘制渐变 + tv.getPaint().setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + return true; + } + }); + } + + private void applyRainbowColors(float phaseOffset) { + if (!sDynamicGradient) return; + + /* 实时读取主题色的 HSV */ + float[] hsv = new float[3]; + Color.colorToHSV(ThemeManager.getInstance().getThemeColor(), hsv); + float baseHue = hsv[0]; + float sat = hsv[1]; // 真实饱和度 + float val = hsv[2]; // 真实亮度 + + synchronized (activeModules) { + for (int i = 0; i < activeModules.size(); i++) { + String moduleName = activeModules.get(i); + LinearLayout row = moduleViews.get(moduleName); + if (row == null) continue; + + final TextView main = (TextView) row.findViewWithTag("main"); + if (main == null) continue; + + /* 1. 计算整段彩虹(基于实时主题色) */ + float offset = i * 15f; + float topHue = (baseHue + offset + phaseOffset) % 360f; + float bottomHue = (topHue + 30f) % 360f; + final int topColor = Color.HSVToColor(new float[]{topHue, sat, val}); + final int bottomColor = Color.HSVToColor(new float[]{bottomHue, sat, val}); + + /* 2. 纯色给边框 */ + main.setTextColor(topColor); + + /* 3. 纵向彩虹覆盖文字 */ + main.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + main.getViewTreeObserver().removeOnPreDrawListener(this); + LinearGradient gradient = new LinearGradient( + 0, 0, + 0, main.getHeight(), + new int[]{topColor, bottomColor}, + null, + Shader.TileMode.CLAMP); + main.getPaint().setShader(gradient); + main.getPaint().setXfermode(null); + return true; + } + }); + } + } + } + + private void applyStaticColor() { + synchronized (activeModules) { + for (String moduleName : activeModules) { + LinearLayout row = moduleViews.get(moduleName); + if (row != null) { + TextView main = (TextView) row.findViewWithTag("main"); + if (main != null) main.setTextColor(mStaticColor); + } + } + } + } + + @Override + public void onThemeColorChanged(int newColor) { + mStaticColor = newColor; + if (!sDynamicGradient) { + applyStaticColor(); // 纯色 + } else { + applyRainbowColors(0f); // 立即重算彩虹(动画会在下一帧继续) + } + invalidate(); // 重绘边框 + } + + private static float dpToPx(float dp) { + return dp * Resources.getSystem().getDisplayMetrics().density; + } + + public static void setGlowEnabled(boolean enable) { + sGlowEnabled = enable; + if (sInstance != null) sInstance.invalidate(); + } + + public static void setBackgroundAlpha(int alpha) { + if (alpha < 0) alpha = 0; + if (alpha > 255) alpha = 255; + sBgAlpha = alpha; + if (sInstance != null) { + sInstance.post(new Runnable() { + public void run() { + synchronized (sInstance.activeModules) { + for (String name : sInstance.activeModules) { + LinearLayout row = sInstance.moduleViews.get(name); + if (row != null && row.getBackground() instanceof GradientDrawable) { + ((GradientDrawable) row.getBackground()).setAlpha(sBgAlpha); + } + } + } + } + }); + } + } + + public class GradientTextDrawable extends Drawable { + private final TextView textView; + private final int topColor; + private final int bottomColor; + private LinearGradient gradient; + + public GradientTextDrawable(TextView textView, int topColor, int bottomColor) { + this.textView = textView; + this.topColor = topColor; + this.bottomColor = bottomColor; + } + + private void updateGradient() { + gradient = new LinearGradient( + 0, 0, 0, textView.getHeight(), + topColor, bottomColor, + Shader.TileMode.CLAMP + ); + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (gradient == null || textView.getHeight() > 0) { + updateGradient(); + } + textView.getPaint().setShader(gradient); + textView.getPaint().setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + textView.draw(canvas); + } + + + + @Override + public void setAlpha(int alpha) {} + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) {} + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + } + + public static class SmoothInterpolator implements android.view.animation.Interpolator { + // 三阶贝塞尔参数:P1(0.25,0.1) P2(0.25,1) —— 类似 iOS 的 ease-out + private static final float P1_X = 0.25f; + private static final float P1_Y = 0.1f; + private static final float P2_X = 0.25f; + private static final float P2_Y = 1.00f; + + private static final float DURATION = 1f; // 归一化时长 + private final float[] mX; // 查找表 + private final float[] mY; + private static final int STEP = 256; + + public SmoothInterpolator() { + mX = new float[STEP + 1]; + mY = new float[STEP + 1]; + for (int i = 0; i <= STEP; i++) { + float t = i / (float) STEP; + mX[i] = cubic(t, 0, P1_X, P2_X, 1); + mY[i] = cubic(t, 0, P1_Y, P2_Y, 1); + } + } + + @Override public float getInterpolation(float input) { + // 二分查找 + int l = 0, r = STEP; + while (l <= r) { + int m = (l + r) >> 1; + if (mX[m] < input) l = m + 1; + else r = m - 1; + } + int idx = Math.max(0, Math.min(STEP - 1, l)); + float x0 = mX[idx]; + float x1 = mX[idx + 1]; + float y0 = mY[idx]; + float y1 = mY[idx + 1]; + float t = (input - x0) / (x1 - x0); + return y0 + t * (y1 - y0); + } + + private float cubic(float t, float a, float b, float c, float d) { + return (float) (Math.pow(1 - t, 3) * a + + 3 * Math.pow(1 - t, 2) * t * b + + 3 * (1 - t) * t * t * c + + Math.pow(t, 3) * d); + } + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ArrayListView.java.bak b/app/src/main/java/com/bytecat/algui/effect/ArrayListView.java.bak new file mode 100644 index 0000000..24e0d14 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ArrayListView.java.bak @@ -0,0 +1,691 @@ +// ========= 第一段:类头、成员变量、接口实现 ========= +package com.bytecat.algui.effect; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.LayoutTransition; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.*; +import android.view.*; +import android.widget.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import android.content.res.Resources; +import android.view.animation.*; +import android.animation.*; +import android.graphics.drawable.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import androidx.annotation.*; +import android.text.style.*; +import android.text.*; + + +public class ArrayListView extends LinearLayout implements ThemeManager.OnThemeColorChangeListener { + + private final Map moduleViews = new ConcurrentHashMap(); + private int mStaticColor = ThemeManager.getInstance().getThemeColor(); + private static boolean sGlowEnabled = true; + private final Paint glowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private static ArrayListView sInstance; + private static boolean sDynamicGradient = true; + private static int sBgAlpha = 255; + + private final List activeModules = Collections.synchronizedList(new ArrayList()); + private ValueAnimator rainbowAnimator; + private final Paint borderPaint = new Paint(); + private final Map animationStates = new ConcurrentHashMap(); + + + private enum ModuleStatus { ADDING, ACTIVE, REMOVING } + private final Map moduleStatuses = new ConcurrentHashMap(); + + private static class BorderAnimationState { + ValueAnimator animator; + float progress = 0f; + float connectionStartX; + float connectionProgress = 1f; + final ArrayListView parent; + BorderAnimationState(ArrayListView parent) { this.parent = parent; } + + void animate(boolean appearing, final Runnable onEndAction) { + if (animator != null && animator.isRunning()) animator.cancel(); + float start = appearing ? progress : 1f; + float end = appearing ? 1f : 0f; + animator = ValueAnimator.ofFloat(start, end); + animator.setDuration(300); + animator.setInterpolator(new AccelerateDecelerateInterpolator()); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + progress = (Float) animation.getAnimatedValue(); + parent.invalidate(); + } + }); + if (onEndAction != null) { + animator.addListener(new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { onEndAction.run(); } + }); + } + animator.start(); + } + + void animateConnection(float startX) { + this.connectionStartX = startX; + ValueAnimator connAnimator = ValueAnimator.ofFloat(0f, 1f); + connAnimator.setDuration(300); + connAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); + connAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + connectionProgress = (Float) animation.getAnimatedValue(); + parent.invalidate(); + } + }); + connAnimator.start(); + } + } + + public ArrayListView(Context context) { + super(context); + setOrientation(LinearLayout.VERTICAL); + setGravity(Gravity.END); + setClipChildren(false); + setClipToPadding(false); + + borderPaint.setStyle(Paint.Style.STROKE); + borderPaint.setAntiAlias(true); + borderPaint.setStrokeWidth(dpToPx(1.5f)); + + LayoutTransition lt = new LayoutTransition(); + lt.setStagger(LayoutTransition.CHANGING, 30); + lt.setDuration(300); + lt.disableTransitionType(LayoutTransition.APPEARING); + lt.disableTransitionType(LayoutTransition.DISAPPEARING); + setLayoutTransition(lt); + + sInstance = this; + + ModuleManager.getInstance().addOnModuleAddedListener(new ModuleManager.ModuleListener() { + @Override + public void onEvent(String moduleName) { + addModule(moduleName); + } + }); + + ModuleManager.getInstance().addOnModuleRemovedListener(new ModuleManager.ModuleListener() { + @Override + public void onEvent(String moduleName) { + removeModule(moduleName); + } + }); + + ModuleManager.getInstance().addOnNotificationListener(new ModuleManager.ModuleListener() { + @Override + public void onEvent(String moduleName) { + refreshModuleSubtitle(moduleName); + } + }); + ModuleManager.getInstance().addOnNotificationListener(new ModuleManager.ModuleListener() { + public void onEvent(String moduleName) { + refreshModuleSubtitle(moduleName); + refreshModuleTitle(moduleName); // 新增 + } + }); + + ThemeManager.getInstance().addListener(this); + } + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + synchronized (activeModules) { + for (int i = 0; i < activeModules.size(); i++) { + String moduleName = activeModules.get(i); + if (moduleStatuses.get(moduleName) == ModuleStatus.REMOVING) continue; + + LinearLayout currentContainer = moduleViews.get(moduleName); + TextView mainTextView = findMainTextView(currentContainer); + BorderAnimationState state = animationStates.get(moduleName); + + if (currentContainer == null || mainTextView == null || state == null) continue; + + int currentColor = mainTextView.getCurrentTextColor(); + + // 找到下一个可见模块颜色 + TextView nextMainTextView = null; + for (int j = i + 1; j < activeModules.size(); j++) { + String nextModuleName = activeModules.get(j); + if (moduleStatuses.get(nextModuleName) != ModuleStatus.REMOVING) { + nextMainTextView = findMainTextView(moduleViews.get(nextModuleName)); + break; + } + } + int nextColor = (nextMainTextView != null) + ? nextMainTextView.getCurrentTextColor() + : currentColor; + + // 为当前文字设置上下渐变(当前 -> 下一模块颜色) + applyTextGradient(mainTextView, currentColor, nextColor); + + // —— 以下边框绘制逻辑不变 —— + float left = currentContainer.getLeft() + currentContainer.getTranslationX(); + float top = currentContainer.getTop(); + float right = currentContainer.getRight() + currentContainer.getTranslationX(); + float bottom = currentContainer.getBottom(); + + LinearLayout nextContainer = null; + for (int j = i + 1; j < activeModules.size(); j++) { + String nextModuleName = activeModules.get(j); + if (moduleStatuses.get(nextModuleName) != ModuleStatus.REMOVING) { + nextContainer = moduleViews.get(nextModuleName); + break; + } + } + + // 上边框 + if (i == 0) { + setShader(borderPaint, null); + borderPaint.setColor(currentColor); + canvas.drawLine(left, top, + left + (right - left) * state.progress, top, borderPaint); + } + + // 左边框(垂直渐变) + LinearGradient verticalGradient = new LinearGradient( + left, top, left, bottom, + new int[]{currentColor, nextColor}, + new float[]{0f, 1f}, + Shader.TileMode.CLAMP); + setShader(borderPaint, verticalGradient); + canvas.drawLine(left, top, + left, top + (bottom - top) * state.progress, borderPaint); + + // 连接线 / 下边框 + if (nextContainer != null) { + float nextLeft = nextContainer.getLeft() + nextContainer.getTranslationX(); + float targetX = nextLeft; + if (state.connectionProgress < 1f) { + targetX = state.connectionStartX + + (nextLeft - state.connectionStartX) * state.connectionProgress; + } + LinearGradient horizontalGradient = new LinearGradient( + left, bottom, targetX, bottom, + new int[]{nextColor, nextColor}, + new float[]{0f, 1f}, + Shader.TileMode.CLAMP); + setShader(borderPaint, horizontalGradient); + canvas.drawLine(left, bottom, + left + (targetX - left) * state.progress, bottom, borderPaint); + } else { + setShader(borderPaint, null); + borderPaint.setColor(currentColor); + canvas.drawLine(left, bottom, + left + (right - left) * state.progress, bottom, borderPaint); + } + } + setShader(borderPaint, null); + } + } + + private void setShader(Paint paint, Shader shader) { + paint.setShader(shader); + if (sGlowEnabled) { + glowPaint.set(paint); // 同步发光画笔 + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int extraW = (int) dpToPx(60); + int extraH = (int) dpToPx(25); + setMeasuredDimension(getMeasuredWidth() + extraW, getMeasuredHeight() + extraH); + } + + private void refreshModuleSubtitle(final String moduleName) { + post(new Runnable() { + public void run() { + LinearLayout row = moduleViews.get(moduleName); + if (row == null) return; + TextView sub = (TextView) row.findViewWithTag("sub"); + if (sub != null) { + sub.setText(ModuleManager.getInstance().getModuleSubtitle(moduleName)); + sortModulesByWidth(); + } + } + }); + } + + private void refreshModuleTitle(final String moduleName) { + post(new Runnable() { + public void run() { + LinearLayout row = moduleViews.get(moduleName); + if (row == null) return; + TextView main = (TextView) row.findViewWithTag("main"); + if (main != null) { + main.setText(ModuleManager.getInstance().getModuleTitle(moduleName)); + sortModulesByWidth(); // 宽度可能变化,重新排序 + } + } + }); + } + + private void addModule(final String moduleName) { + if (moduleStatuses.get(moduleName) == ModuleStatus.REMOVING) { + moduleStatuses.put(moduleName, ModuleStatus.ACTIVE); + final LinearLayout moduleText = moduleViews.get(moduleName); + final BorderAnimationState state = animationStates.get(moduleName); + if (moduleText != null && state != null) { + post(new Runnable() { + public void run() { + moduleText.animate().cancel(); + state.animate(true, null); + moduleText.animate().alpha(1f).scaleX(1f).scaleY(1f).translationX(0f).setDuration(300).start(); + } + }); + } + return; + } + if (moduleStatuses.containsKey(moduleName)) return; + + moduleStatuses.put(moduleName, ModuleStatus.ADDING); + final LinearLayout moduleLayout = createModuleLayout(moduleName); + moduleViews.put(moduleName, moduleLayout); + + int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + moduleLayout.measure(spec, spec); + final int newModuleWidth = moduleLayout.getMeasuredWidth(); + final BorderAnimationState state = new BorderAnimationState(this); + animationStates.put(moduleName, state); + + post(new Runnable() { + public void run() { + int newIndex = 0; + synchronized (activeModules) { + for (String existingModuleName : activeModules) { + if (moduleStatuses.get(existingModuleName) == ModuleStatus.REMOVING) continue; + View existingView = moduleViews.get(existingModuleName); + if (existingView != null && newModuleWidth > existingView.getMeasuredWidth()) { + break; + } + newIndex++; + } + } + + if (newIndex > activeModules.size()) newIndex = activeModules.size(); + activeModules.add(newIndex, moduleName); + addView(moduleLayout, newIndex); + + final Runnable endAction = new Runnable() { + public void run() { + moduleStatuses.put(moduleName, ModuleStatus.ACTIVE); + } + }; + TimeInterpolator fastInSlowEnd = new TimeInterpolator() { + public float getInterpolation(float input) { + return 1f - (1f - input) * (1f - input); + } + }; + + moduleLayout.setAlpha(0f); + moduleLayout.setTranslationX(getWidth()); + moduleLayout.animate() + .alpha(1f) + .translationX(0f) + .setDuration(400) + .setInterpolator(fastInSlowEnd) + .withEndAction(endAction) + .start(); + + state.animate(true, null); + } + }); + } + + private void removeModule(final String moduleName) { + if (!moduleStatuses.containsKey(moduleName) || moduleStatuses.get(moduleName) == ModuleStatus.REMOVING) { + return; + } + moduleStatuses.put(moduleName, ModuleStatus.REMOVING); + final LinearLayout moduleText = moduleViews.get(moduleName); + final BorderAnimationState state = animationStates.get(moduleName); + if (moduleText == null || state == null) return; + + final int currentIndex = activeModules.indexOf(moduleName); + if (currentIndex > 0) { + for (int i = currentIndex - 1; i >= 0; i--) { + String prevModuleName = activeModules.get(i); + if (moduleStatuses.get(prevModuleName) != ModuleStatus.REMOVING) { + BorderAnimationState prevState = animationStates.get(prevModuleName); + if (prevState != null) prevState.animateConnection(moduleText.getLeft()); + break; + } + } + } + + final Runnable endAction = new Runnable() { + public void run() { + moduleStatuses.remove(moduleName); + moduleViews.remove(moduleName); + animationStates.remove(moduleName); + activeModules.remove(moduleName); + removeView(moduleText); + } + }; + + post(new Runnable() { + public void run() { + moduleText.animate().cancel(); + state.animate(false, null); + moduleText.animate() + .alpha(0f) + .translationX(moduleText.getWidth()) + .setDuration(300) + .setInterpolator(new AccelerateDecelerateInterpolator()) + .withEndAction(endAction) + .start(); + } + }); + } + + private void sortModulesByWidth() { + synchronized (activeModules) { + List viewDataList = (List) new ArrayList(); + for (String moduleName : activeModules) { + if (moduleStatuses.get(moduleName) != ModuleStatus.REMOVING) { + viewDataList.add(new ViewData(moduleName, moduleViews.get(moduleName))); + } + } + + Collections.sort(viewDataList, new Comparator() { + public int compare(ViewData o1, ViewData o2) { + return o2.view.getMeasuredWidth() - o1.view.getMeasuredWidth(); + } + }); + + activeModules.clear(); + for (ViewData data : viewDataList) { + activeModules.add(data.name); + data.view.bringToFront(); + } + } + requestLayout(); + invalidate(); + } + + private static class ViewData { + String name; + View view; + ViewData(String name, View view) { + this.name = name; + this.view = view; + } + } + + private LinearLayout createModuleLayout(final String moduleName) { + Context ctx = getContext(); + LinearLayout row = new LinearLayout(ctx); + row.setOrientation(LinearLayout.HORIZONTAL); + row.setGravity(Gravity.END | Gravity.BOTTOM); + row.setBackgroundColor(Color.parseColor("#80FFFFFF")); + row.setPadding((int) dpToPx(4), 0, (int) dpToPx(4), 0); + + int h = (int) dpToPx(16); + + TextView main = new TextView(ctx); + main.setTag("main"); + main.setText(ModuleManager.getInstance().getModuleTitle(moduleName)); + main.setTextSize(12); + main.setTextColor(Color.WHITE); + main.setGravity(Gravity.BOTTOM | Gravity.END); + + + LinearLayout.LayoutParams lpMain = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, h); + lpMain.gravity = Gravity.BOTTOM | Gravity.END; + main.setLayoutParams(lpMain); + + + TextView sub = new TextView(ctx); + sub.setTag("sub"); + sub.setText(ModuleManager.getInstance().getModuleSubtitle(moduleName)); + sub.setTextSize(10); + sub.setTextColor(Color.parseColor("#85000000")); + sub.setGravity(Gravity.BOTTOM | Gravity.END); + sub.setMinHeight(h); + try { + Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/TrosCore.ttf"); + sub.setTypeface(tf); + } catch (Exception e) { + // ignore + } + LinearLayout.LayoutParams lpSub = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + lpSub.gravity = Gravity.BOTTOM | Gravity.END; + lpSub.leftMargin = (int) dpToPx(2); + sub.setLayoutParams(lpSub); + + row.addView(main); + row.addView(sub); + + LinearLayout.LayoutParams rowLp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + row.setLayoutParams(rowLp); + return row; + } + + private TextView findMainTextView(LinearLayout container) { + if (container == null) return null; + return (TextView) container.findViewWithTag("main"); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + startRainbowAnimation(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + stopRainbowAnimation(); + } + + public static void setDynamicGradient(boolean enable) { + if (sInstance == null) return; + sDynamicGradient = enable; + if (enable) sInstance.startRainbowAnimation(); + else sInstance.stopRainbowAnimation(); + } + + private void startRainbowAnimation() { + if (rainbowAnimator != null && rainbowAnimator.isRunning()) return; + rainbowAnimator = ValueAnimator.ofFloat(0f, 360f); + rainbowAnimator.setDuration(8000); + rainbowAnimator.setRepeatCount(ValueAnimator.INFINITE); + rainbowAnimator.setInterpolator(new LinearInterpolator()); + rainbowAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + if (!sDynamicGradient) return; + applyRainbowColors((Float) animation.getAnimatedValue()); + invalidate(); + } + }); + rainbowAnimator.start(); + } + + private void stopRainbowAnimation() { + if (rainbowAnimator != null) { + rainbowAnimator.cancel(); + rainbowAnimator = null; + } + } + + private void applyTextGradient(final TextView tv, final int topColor, final int bottomColor) { + tv.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + tv.getViewTreeObserver().removeOnPreDrawListener(this); + + LinearGradient gradient = new LinearGradient( + 0, 0, 0, tv.getHeight(), + topColor, bottomColor, + Shader.TileMode.CLAMP + ); + tv.getPaint().setShader(gradient); + // 用 SRC_IN 只在文字区域绘制渐变 + tv.getPaint().setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + return true; + } + }); + } + + private void applyRainbowColors(float phaseOffset) { + if (!sDynamicGradient) return; + + /* 实时读取主题色的 HSV */ + float[] hsv = new float[3]; + Color.colorToHSV(ThemeManager.getInstance().getThemeColor(), hsv); + float baseHue = hsv[0]; + float sat = hsv[1]; // 真实饱和度 + float val = hsv[2]; // 真实亮度 + + synchronized (activeModules) { + for (int i = 0; i < activeModules.size(); i++) { + String moduleName = activeModules.get(i); + LinearLayout row = moduleViews.get(moduleName); + if (row == null) continue; + + final TextView main = (TextView) row.findViewWithTag("main"); + if (main == null) continue; + + /* 1. 计算整段彩虹(基于实时主题色) */ + float offset = i * 15f; + float topHue = (baseHue + offset + phaseOffset) % 360f; + float bottomHue = (topHue + 30f) % 360f; + final int topColor = Color.HSVToColor(new float[]{topHue, sat, val}); + final int bottomColor = Color.HSVToColor(new float[]{bottomHue, sat, val}); + + /* 2. 纯色给边框 */ + main.setTextColor(topColor); + + /* 3. 纵向彩虹覆盖文字 */ + main.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + main.getViewTreeObserver().removeOnPreDrawListener(this); + LinearGradient gradient = new LinearGradient( + 0, 0, + 0, main.getHeight(), + new int[]{topColor, bottomColor}, + null, + Shader.TileMode.CLAMP); + main.getPaint().setShader(gradient); + main.getPaint().setXfermode(null); + return true; + } + }); + } + } + } + + private void applyStaticColor() { + synchronized (activeModules) { + for (String moduleName : activeModules) { + LinearLayout row = moduleViews.get(moduleName); + if (row != null) { + TextView main = (TextView) row.findViewWithTag("main"); + if (main != null) main.setTextColor(mStaticColor); + } + } + } + } + + @Override + public void onThemeColorChanged(int newColor) { + mStaticColor = newColor; + if (!sDynamicGradient) { + applyStaticColor(); // 纯色 + } else { + applyRainbowColors(0f); // 立即重算彩虹(动画会在下一帧继续) + } + invalidate(); // 重绘边框 + } + + private static float dpToPx(float dp) { + return dp * Resources.getSystem().getDisplayMetrics().density; + } + + public static void setGlowEnabled(boolean enable) { + sGlowEnabled = enable; + if (sInstance != null) sInstance.invalidate(); + } + + public static void setBackgroundAlpha(int alpha) { + if (alpha < 0) alpha = 0; + if (alpha > 255) alpha = 255; + sBgAlpha = alpha; + if (sInstance != null) { + sInstance.post(new Runnable() { + public void run() { + synchronized (sInstance.activeModules) { + for (String name : sInstance.activeModules) { + LinearLayout row = sInstance.moduleViews.get(name); + if (row != null && row.getBackground() instanceof GradientDrawable) { + ((GradientDrawable) row.getBackground()).setAlpha(sBgAlpha); + } + } + } + } + }); + } + } + + public class GradientTextDrawable extends Drawable { + private final TextView textView; + private final int topColor; + private final int bottomColor; + private LinearGradient gradient; + + public GradientTextDrawable(TextView textView, int topColor, int bottomColor) { + this.textView = textView; + this.topColor = topColor; + this.bottomColor = bottomColor; + } + + private void updateGradient() { + gradient = new LinearGradient( + 0, 0, 0, textView.getHeight(), + topColor, bottomColor, + Shader.TileMode.CLAMP + ); + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (gradient == null || textView.getHeight() > 0) { + updateGradient(); + } + textView.getPaint().setShader(gradient); + textView.getPaint().setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + textView.draw(canvas); + } + + + + @Override + public void setAlpha(int alpha) {} + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) {} + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + } + + + +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ClickFX.java b/app/src/main/java/com/bytecat/algui/effect/ClickFX.java new file mode 100644 index 0000000..b04f927 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ClickFX.java @@ -0,0 +1,84 @@ +package com.bytecat.algui.effect; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.view.ViewAnimationUtils; + +import com.bytecat.algui.animation.Animated; +import com.bytecat.algui.animation.AnimatedSet; +import com.bytecat.algui.animation.ObjectAnimated; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.PostCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.util.GradientDrawableBuilder; + +public final class ClickFX extends BaseHelper { + + private final Popup popup; + + private final Column column; + + private int x, y; + + private long duration; + + public ClickFX() { + column = new Column() + .setAlpha(0f) + .setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#22000000")) + ) + .postOnce(new PostCallback() { + @Override + public void onPost(int width, int height) { + Animator revealAnimator = ViewAnimationUtils.createCircularReveal( + column.build(), x, y, 0f, SystemH() + ); + revealAnimator.setDuration(1000L); + + new AnimatedSet() + .setDuration(duration) + .playTogether( + new Animated(revealAnimator), + new ObjectAnimated() + .setPropertyName("alpha") + .ofFloat(1f, 0f) + .setTarget(column) + .addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationEnd(Animator animation) { + dismiss(); + } + + }) + ) + .start(); + } + }); + + popup = new Popup() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setFocusable(false) + .setContentView(column); + } + + public Popup show(int x, int y, long duration) { + this.x = x; + this.y = y; + this.duration = duration; + return popup.show(); + } + + public Popup show(int x, int y) { + return show(x, y, 1000L); + } + + public Popup dismiss() { + return popup.dismiss(); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ColorPickerPopup.java b/app/src/main/java/com/bytecat/algui/effect/ColorPickerPopup.java new file mode 100644 index 0000000..73ad421 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ColorPickerPopup.java @@ -0,0 +1,65 @@ +package com.bytecat.algui.effect; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import com.bytecat.algui.component.Text; + +public class ColorPickerPopup extends LinearLayout { + + public interface OnColorChangeListener { + void onColorChanged(int color); + } + + private boolean isExpanded = false; + private final ColorPickerView pickerView; + private final Text toggleBtn; + private OnColorChangeListener listener; + + public ColorPickerPopup(Context ctx) { + super(ctx); + setOrientation(VERTICAL); + setGravity(Gravity.END); + + // 折叠按钮 + toggleBtn = new Text() + .setText("🎨") + .setTextSize(14) + .setTextColor(Color.WHITE) + .setPadding(dp(4), dp(2), dp(4), dp(2)); + GradientDrawable bg = new GradientDrawable(); + bg.setColor(Color.parseColor("#B32C2C32")); + bg.setCornerRadius(dp(6)); + toggleBtn.build().setBackground(bg); + + // 调色板 + pickerView = new ColorPickerView(ctx); + pickerView.setVisibility(GONE); + + // 点击切换 + toggleBtn.build().setOnClickListener(new OnClickListener() { + @Override public void onClick(View v) { + isExpanded = !isExpanded; + pickerView.setVisibility(isExpanded ? VISIBLE : GONE); + } + }); + + addView(toggleBtn.build()); + addView(pickerView); + } + + public void setOnColorChangeListener(OnColorChangeListener l) { + this.listener = l; + } + + public void setToggleText(String text) { + toggleBtn.setText(text); + } + + private int dp(int dp) { + return (int) (getResources().getDisplayMetrics().density * dp + 0.5f); + } +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ColorPickerView.java b/app/src/main/java/com/bytecat/algui/effect/ColorPickerView.java new file mode 100644 index 0000000..b809706 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ColorPickerView.java @@ -0,0 +1,131 @@ +package com.bytecat.algui.effect; + +import android.content.Context; +import android.graphics.*; +import android.graphics.drawable.GradientDrawable; +import android.view.MotionEvent; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.SeekBar; + + +public class ColorPickerView extends LinearLayout { + + private ColorPaletteView paletteView; + private SeekBar hueSlider; + private float currentHue = 184f; + private float currentSat = 0.55f; // from left: 55% + private float currentVal = 0.55f; // from top: 45% -> value is 1 - 0.45 = 0.55 + + public ColorPickerView(Context context) { + super(context); + setOrientation(VERTICAL); + setPadding(0, dpToPx(5), 0, 0); + + paletteView = new ColorPaletteView(context); + addView(paletteView, new LayoutParams(LayoutParams.MATCH_PARENT, dpToPx(80))); + + hueSlider = new SeekBar(context); + hueSlider.setMax(360); + hueSlider.setProgress((int) currentHue); + + // Create hue gradient for the slider + int[] hueColors = new int[361]; + for (int i = 0; i < hueColors.length; i++) { + hueColors[i] = Color.HSVToColor(new float[]{i, 1f, 1f}); + } + GradientDrawable hueGradient = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, hueColors); + hueSlider.setProgressDrawable(hueGradient); + + LayoutParams sliderParams = new LayoutParams(LayoutParams.MATCH_PARENT, dpToPx(8)); + sliderParams.setMargins(0, dpToPx(8), 0, 0); + hueSlider.setLayoutParams(sliderParams); + hueSlider.getThumb().setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + + hueSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + currentHue = progress; + paletteView.setHue(currentHue); + updateThemeColor(); + } + @Override public void onStartTrackingTouch(SeekBar seekBar) {} + @Override public void onStopTrackingTouch(SeekBar seekBar) {} + }); + + addView(hueSlider); + updateThemeColor(); + } + + private void updateThemeColor() { + float[] hsv = {currentHue, currentSat, currentVal}; + int color = Color.HSVToColor(hsv); + ThemeManager.getInstance().setThemeColor(color); + } + + private int dpToPx(int dp) { + return (int) (dp * getResources().getDisplayMetrics().density); + } + + private class ColorPaletteView extends View { + private Paint saturationPaint, valuePaint; + private Paint indicatorPaint; + private Shader valueShader, saturationShader; + private float hue = 184f; + private float indicatorX, indicatorY; + + public ColorPaletteView(Context context) { + super(context); + saturationPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + valuePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + indicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + indicatorPaint.setStyle(Paint.Style.STROKE); + indicatorPaint.setStrokeWidth(dpToPx(2)); + indicatorPaint.setColor(Color.WHITE); + setHue(hue); + } + + public void setHue(float hue) { + this.hue = hue; + if (getWidth() > 0) { + int hueColor = Color.HSVToColor(new float[]{hue, 1f, 1f}); + saturationShader = new LinearGradient(0, 0, getWidth(), 0, Color.WHITE, hueColor, Shader.TileMode.CLAMP); + saturationPaint.setShader(saturationShader); + } + invalidate(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + valueShader = new LinearGradient(0, 0, 0, h, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP); + valuePaint.setShader(valueShader); + setHue(hue); // Re-apply shader with correct width + indicatorX = w * currentSat; + indicatorY = h * (1 - currentVal); + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.drawRect(0, 0, getWidth(), getHeight(), saturationPaint); + canvas.drawRect(0, 0, getWidth(), getHeight(), valuePaint); + canvas.drawCircle(indicatorX, indicatorY, dpToPx(6), indicatorPaint); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + indicatorX = Math.max(0, Math.min(getWidth(), event.getX())); + indicatorY = Math.max(0, Math.min(getHeight(), event.getY())); + currentSat = indicatorX / getWidth(); + currentVal = 1 - (indicatorY / getHeight()); + updateThemeColor(); + invalidate(); + return true; + } + return super.onTouchEvent(event); + } + } +} diff --git a/app/src/main/java/com/bytecat/algui/effect/DynamicArrayList.java b/app/src/main/java/com/bytecat/algui/effect/DynamicArrayList.java new file mode 100644 index 0000000..ca11cb8 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/DynamicArrayList.java @@ -0,0 +1,58 @@ +package com.bytecat.algui.effect; + +import android.graphics.Color; +import android.os.Handler; +import android.os.Looper; + +public class DynamicArrayList extends ArrayList { + + private static DynamicArrayList instance; + + private final Handler handler = new Handler(Looper.getMainLooper()); + private float offset = 0.0f; // 改为 float,支持小数步进 + + public DynamicArrayList() { + handler.post(new Runnable() { + @Override + public void run() { + updateColors(); + handler.postDelayed(this, 30L); // 100 ms 更新一次 + } + }); + } + + /* ================= 核心:斜向彩虹 ================= */ + private void updateColors() { + for (int i = 0; i < items.size(); i++) { + Item item = items.get(i); + int textColor = calculateGradientColor(offset, i); + item.setTextColor(textColor); + item.setStripeColor(textColor); + + // 在 updateColors() 里同步修改 + + } + offset = (offset + 0.5f) % 256f; // 步长 0.2,速度更慢 + } + + private int calculateGradientColor(float offset, int index) { + // 斜向距离:index 越大越“右”,offset 越大越“下” + float diagonal = index * 10.0f + offset; + int safeOffset = ((int) diagonal) & 0xFF; // 0~255 循环 + + double phase = safeOffset / 255.0 * 2.0 * Math.PI; + int r = (int) (Math.sin(phase) * 127 + 128); + int g = (int) (Math.sin(phase + 2.0 * Math.PI / 3.0) * 127 + 128); + int b = (int) (Math.sin(phase + 4.0 * Math.PI / 3.0) * 127 + 128); + + return Color.rgb(r, g, b); + } + /* ================================================ */ + + public static DynamicArrayList getInstance() { + if (instance == null) { + instance = new DynamicArrayList(); + } + return instance; + } +} diff --git a/app/src/main/java/com/bytecat/algui/effect/Hint.java b/app/src/main/java/com/bytecat/algui/effect/Hint.java new file mode 100644 index 0000000..bfb4d6c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/Hint.java @@ -0,0 +1,90 @@ +package com.bytecat.algui.effect; + +import android.view.Gravity; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.util.GradientDrawableBuilder; + +public final class Hint extends Popup { + + private static Hint lastHint; + + private Text text; + + private boolean autoCancel = true; + + public Hint() { + setWidth(BaseHelper.WrapContent); + setHeight(BaseHelper.WrapContent); + setFocusable(false); + setTouchable(false); + setGravity(Gravity.CENTER | Gravity.BOTTOM); + setPosition(0, (int) (H() * 0.12f)); + setAnimation(Animation.Toast); + + Column column = new Column() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ); + setContentView(column); + + Column container = new Column() + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(30f) + .setColor(hexColor("#FFFFFFFF")) + ) + .setGravity(Gravity.CENTER) + .setElevation(40f) + .setLayoutParams( + new LinearParams() + .setAllMargins(dip2pxInt(25)) + ); + column.addView(container); + + text = new Text() + .setGravity(Gravity.CENTER) + .setTextSize(13f) + .setTextColor(hexColor("#FF000000")) + .setPadding(30, 30, 30, 30); + container.addView(text); + } + + public Hint setAutoCancel(boolean autoCancel) { + this.autoCancel = autoCancel; + return this; + } + + public Hint setMessage(String message) { + text.setText(message); + return this; + } + + @Override + public Popup show() { + if (lastHint != null) { + lastHint.setContentView(new Widget()); + } + final Popup popup = super.show(); + lastHint = this; + if (autoCancel) { + delayed(new Runnable() { + @Override + public void run() { + if (autoCancel) { + popup.dismiss(); + } + } + }, 2500L); + } + return popup; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ModuleManager.java b/app/src/main/java/com/bytecat/algui/effect/ModuleManager.java new file mode 100644 index 0000000..f4b19e0 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ModuleManager.java @@ -0,0 +1,213 @@ +package com.bytecat.algui.effect; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ModuleManager { + + private static ModuleManager instance; + + /* 统一保存模块状态 + 主标题 + 副标题 */ + private final Map moduleStates = new HashMap(); + + private final List onModuleAddedListeners = new ArrayList(); + private final List onModuleRemovedListeners = new ArrayList(); + private final List onNotificationListeners = new ArrayList(); + + private ModuleManager() {} + + public static synchronized ModuleManager getInstance() { + if (instance == null) { + instance = new ModuleManager(); + } + return instance; + } + + /* 内部统一读取最终显示标题 */ + private String getDisplayTitle(String rawKey) { + /* 1. 如果开发者手动设置了标题,直接用 */ + ModuleData data = moduleStates.get(rawKey); + if (data != null && data.title != null && data.title.length() > 0) { + return data.title; + } + + /* 2. 否则走中英文切换逻辑 */ + if (rawKey == null) return ""; + int idx = rawKey.indexOf('|'); + if (idx < 0) return rawKey; + String zh = rawKey.substring(0, idx); + String en = rawKey.substring(idx + 1); + boolean isChinese = new java.io.File("/sdcard/Android/data/com.vortex.celestial/files/switch.lang").exists(); + return isChinese ? zh : en; + } + + /* ------------------------------------------------ + 1. 旧接口:只设置副标题(保持 100% 向后兼容) + ------------------------------------------------ */ + public void setModuleEnabled(String moduleName, boolean isEnabled) { + setModuleEnabled(moduleName, isEnabled, ""); + } + + public void setModuleEnabled(String moduleName, + boolean isEnabled, + String subtitle) { + innerSetModuleEnabled(moduleName, isEnabled, null, subtitle); + } + + /* ------------------------------------------------ + 2. 新接口:同时设置主、副标题 + ------------------------------------------------ */ + public void setModuleEnabled(String moduleName, + boolean isEnabled, + String title, + String subtitle) { + innerSetModuleEnabled(moduleName, isEnabled, title, subtitle); + } + + /* ------------------------------------------------ + 3. 只改主标题 + ------------------------------------------------ */ + public void setModuleTitle(String moduleName, String newTitle) { + ModuleData d = moduleStates.get(moduleName); + if (d == null) return; + + /* 1. 若传的是 “中文|English” 格式,先解析 */ + String finalTitle = newTitle; + if (finalTitle != null && finalTitle.contains("|")) { + finalTitle = parseLanguage(finalTitle); + } + /* 2. 其余情况(纯文字或 null)保持原值 */ + d.title = (finalTitle == null ? "" : finalTitle); + + /* 3. 通知 UI 刷新 */ + for (ModuleListener l : onNotificationListeners) { + l.onEvent(moduleName); + } + } + + /* ------------------------------------------------ + 4. 只改副标题 + ------------------------------------------------ */ + public void setModuleSubtitle(String moduleName, String newSubtitle) { + ModuleData d = moduleStates.get(moduleName); + if (d == null) return; + d.subtitle = (newSubtitle == null ? "" : newSubtitle); + + for (ModuleListener l : onNotificationListeners) { + l.onEvent(moduleName); + } + } + + /* ------------------------------------------------ + 5. 查询接口 + ------------------------------------------------ */ + public boolean isModuleEnabled(String moduleName) { + ModuleData d = moduleStates.get(moduleName); + return d != null && d.enabled; + } + + public String getModuleTitle(String moduleName) { + return getDisplayTitle(moduleName); + } + + public String getModuleSubtitle(String moduleName) { + ModuleData d = moduleStates.get(moduleName); + return (d == null || d.subtitle == null) ? "" : d.subtitle; + } + + /* ------------------------------------------------ + 6. 监听器注册 + ------------------------------------------------ */ + public void addOnModuleAddedListener(ModuleListener listener) { + onModuleAddedListeners.add(listener); + } + + public void addOnModuleRemovedListener(ModuleListener listener) { + onModuleRemovedListeners.add(listener); + } + + public void addOnNotificationListener(ModuleListener listener) { + onNotificationListeners.add(listener); + } + + /* ================================================= + 内部实现 + ================================================= */ + private void innerSetModuleEnabled(String moduleName, + boolean isEnabled, + String title, + String subtitle) { + ModuleData old = moduleStates.get(moduleName); + boolean wasEnabled = old != null && old.enabled; + + /* 1. 若调用者没传 title,用解析后的当前语言标题 */ + String finalTitle = title; + if (finalTitle == null || finalTitle.length() == 0) { + finalTitle = parseLanguage(moduleName); + } + + /* 2. 若启用状态变化 -> 触发添加/移除事件 */ + if (wasEnabled != isEnabled) { + moduleStates.put(moduleName, + new ModuleData(isEnabled, + finalTitle, + subtitle == null ? "" : subtitle)); + + if (isEnabled) { + for (ModuleListener l : onModuleAddedListeners) { + l.onEvent(moduleName); + } + } else { + for (ModuleListener l : onModuleRemovedListeners) { + l.onEvent(moduleName); + } + } + } else { + /* 仅更新文字 */ + if (old != null) { + if (title != null) old.title = title; + if (subtitle != null) old.subtitle = subtitle; + } + } + } + + private String parseLanguage(String rawKey) { + if (rawKey == null) return ""; + int idx = rawKey.indexOf('|'); + if (idx < 0) return rawKey; + String zh = rawKey.substring(0, idx); + String en = rawKey.substring(idx + 1); + boolean isChinese = new java.io.File("/storage/emulated/0/TC配置文件/switch.lang").exists(); + return isChinese ? zh : en; + } + + public void notifyModuleRemoved(String moduleName) { + for (ModuleListener l : onModuleRemovedListeners) { + l.onEvent(moduleName); + } + } + + /* ================================================= + 内部数据类 + ================================================= */ + public static class ModuleData { + public boolean enabled; + public String title; + public String subtitle; + + ModuleData(boolean enabled, String title, String subtitle) { + this.enabled = enabled; + this.title = (title == null ? "" : title); + this.subtitle = (subtitle == null ? "" : subtitle); + } + } + + /* ================================================= + 监听器接口 + ================================================= */ + public interface ModuleListener { + void onEvent(String moduleName); + } +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ModuleManager.java.bak b/app/src/main/java/com/bytecat/algui/effect/ModuleManager.java.bak new file mode 100644 index 0000000..0939e8b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ModuleManager.java.bak @@ -0,0 +1,213 @@ +package com.bytecat.algui.effect; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ModuleManager { + + private static ModuleManager instance; + + /* 统一保存模块状态 + 主标题 + 副标题 */ + private final Map moduleStates = new HashMap(); + + private final List onModuleAddedListeners = new ArrayList(); + private final List onModuleRemovedListeners = new ArrayList(); + private final List onNotificationListeners = new ArrayList(); + + private ModuleManager() {} + + public static synchronized ModuleManager getInstance() { + if (instance == null) { + instance = new ModuleManager(); + } + return instance; + } + + /* 内部统一读取最终显示标题 */ + private String getDisplayTitle(String rawKey) { + /* 1. 如果开发者手动设置了标题,直接用 */ + ModuleData data = moduleStates.get(rawKey); + if (data != null && data.title != null && data.title.length() > 0) { + return data.title; + } + + /* 2. 否则走中英文切换逻辑 */ + if (rawKey == null) return ""; + int idx = rawKey.indexOf('|'); + if (idx < 0) return rawKey; + String zh = rawKey.substring(0, idx); + String en = rawKey.substring(idx + 1); + boolean isChinese = new java.io.File("/storage/emulated/0/TC配置文件/switch.lang").exists(); + return isChinese ? zh : en; + } + + /* ------------------------------------------------ + 1. 旧接口:只设置副标题(保持 100% 向后兼容) + ------------------------------------------------ */ + public void setModuleEnabled(String moduleName, boolean isEnabled) { + setModuleEnabled(moduleName, isEnabled, ""); + } + + public void setModuleEnabled(String moduleName, + boolean isEnabled, + String subtitle) { + innerSetModuleEnabled(moduleName, isEnabled, null, subtitle); + } + + /* ------------------------------------------------ + 2. 新接口:同时设置主、副标题 + ------------------------------------------------ */ + public void setModuleEnabled(String moduleName, + boolean isEnabled, + String title, + String subtitle) { + innerSetModuleEnabled(moduleName, isEnabled, title, subtitle); + } + + /* ------------------------------------------------ + 3. 只改主标题 + ------------------------------------------------ */ + public void setModuleTitle(String moduleName, String newTitle) { + ModuleData d = moduleStates.get(moduleName); + if (d == null) return; + + /* 1. 若传的是 “中文|English” 格式,先解析 */ + String finalTitle = newTitle; + if (finalTitle != null && finalTitle.contains("|")) { + finalTitle = parseLanguage(finalTitle); + } + /* 2. 其余情况(纯文字或 null)保持原值 */ + d.title = (finalTitle == null ? "" : finalTitle); + + /* 3. 通知 UI 刷新 */ + for (ModuleListener l : onNotificationListeners) { + l.onEvent(moduleName); + } + } + + /* ------------------------------------------------ + 4. 只改副标题 + ------------------------------------------------ */ + public void setModuleSubtitle(String moduleName, String newSubtitle) { + ModuleData d = moduleStates.get(moduleName); + if (d == null) return; + d.subtitle = (newSubtitle == null ? "" : newSubtitle); + + for (ModuleListener l : onNotificationListeners) { + l.onEvent(moduleName); + } + } + + /* ------------------------------------------------ + 5. 查询接口 + ------------------------------------------------ */ + public boolean isModuleEnabled(String moduleName) { + ModuleData d = moduleStates.get(moduleName); + return d != null && d.enabled; + } + + public String getModuleTitle(String moduleName) { + return getDisplayTitle(moduleName); + } + + public String getModuleSubtitle(String moduleName) { + ModuleData d = moduleStates.get(moduleName); + return (d == null || d.subtitle == null) ? "" : d.subtitle; + } + + /* ------------------------------------------------ + 6. 监听器注册 + ------------------------------------------------ */ + public void addOnModuleAddedListener(ModuleListener listener) { + onModuleAddedListeners.add(listener); + } + + public void addOnModuleRemovedListener(ModuleListener listener) { + onModuleRemovedListeners.add(listener); + } + + public void addOnNotificationListener(ModuleListener listener) { + onNotificationListeners.add(listener); + } + + /* ================================================= + 内部实现 + ================================================= */ + private void innerSetModuleEnabled(String moduleName, + boolean isEnabled, + String title, + String subtitle) { + ModuleData old = moduleStates.get(moduleName); + boolean wasEnabled = old != null && old.enabled; + + /* 1. 若调用者没传 title,用解析后的当前语言标题 */ + String finalTitle = title; + if (finalTitle == null || finalTitle.length() == 0) { + finalTitle = parseLanguage(moduleName); + } + + /* 2. 若启用状态变化 -> 触发添加/移除事件 */ + if (wasEnabled != isEnabled) { + moduleStates.put(moduleName, + new ModuleData(isEnabled, + finalTitle, + subtitle == null ? "" : subtitle)); + + if (isEnabled) { + for (ModuleListener l : onModuleAddedListeners) { + l.onEvent(moduleName); + } + } else { + for (ModuleListener l : onModuleRemovedListeners) { + l.onEvent(moduleName); + } + } + } else { + /* 仅更新文字 */ + if (old != null) { + if (title != null) old.title = title; + if (subtitle != null) old.subtitle = subtitle; + } + } + } + + private String parseLanguage(String rawKey) { + if (rawKey == null) return ""; + int idx = rawKey.indexOf('|'); + if (idx < 0) return rawKey; + String zh = rawKey.substring(0, idx); + String en = rawKey.substring(idx + 1); + boolean isChinese = new java.io.File("/storage/emulated/0/TC配置文件/switch.lang").exists(); + return isChinese ? zh : en; + } + + public void notifyModuleRemoved(String moduleName) { + for (ModuleListener l : onModuleRemovedListeners) { + l.onEvent(moduleName); + } + } + + /* ================================================= + 内部数据类 + ================================================= */ + public static class ModuleData { + public boolean enabled; + public String title; + public String subtitle; + + ModuleData(boolean enabled, String title, String subtitle) { + this.enabled = enabled; + this.title = (title == null ? "" : title); + this.subtitle = (subtitle == null ? "" : subtitle); + } + } + + /* ================================================= + 监听器接口 + ================================================= */ + public interface ModuleListener { + void onEvent(String moduleName); + } +} diff --git a/app/src/main/java/com/bytecat/algui/effect/Notification.java b/app/src/main/java/com/bytecat/algui/effect/Notification.java new file mode 100644 index 0000000..432b8e5 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/Notification.java @@ -0,0 +1,239 @@ +package com.bytecat.algui.effect; + +import android.animation.LayoutTransition; +import android.view.Gravity; +import android.view.View; + +import com.bytecat.algui.callback.PostCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.util.GradientDrawableBuilder; + +import java.io.File; + +public class Notification extends Popup { + + private Column column; + + private static Notification instance; + + public Notification() { + setWidth(MatchParent); + setHeight(MatchParent); + setFocusable(false); + setTouchable(false); + setGravity(Gravity.RIGHT | Gravity.BOTTOM); + setContentView(createContentView()); + } + + private Column createContentView() { + column = new Column() + .setGravity(Gravity.BOTTOM); + + LayoutTransition transition = new LayoutTransition(); + column.build().setLayoutTransition(transition); + return column; + } + + public Notification make(String titleText, String message, Type type) { + final Row[] container = new Row[1]; + container[0] = new Row() + .setLayoutParams( + new LinearParams() + .setGravity(Gravity.RIGHT) + .setWidth(WrapContent) + .setHeight(dip2pxInt(50)) + .setAllMargins(dip2pxInt(10)) + ) + .setPadding(0, dip2pxInt(10), 0, dip2pxInt(10)) + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(dip2px(6)) + .setColor(hexColor("#B32C2C32")) + ) + .setElevation(dip2px(8)) + .postOnceDelayed(new PostCallback() { + + @Override + public void onPost(int width, int height) { + if (column.build().getChildCount() > 0) { + for (int i = 0; i < column.build().getChildCount(); i++) { + if (column.build().getChildAt(i) == container[0].build()) { + column.build().removeViewAt(i); + } + } + } + } + + }, Math.max(2500L * column.build().getChildCount(), 2500L)); + + int color; + if (type == Type.ERROR) { + color = hexColor("#CCFF5252"); + } else if (type == Type.WARN) { + color = hexColor("#CCFFB74D"); + } else { + color = hexColor("#CC66BB6A"); + } + + Widget state = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(dip2pxInt(10)) + .setHeight(dip2pxInt(10)) + .setLeftMargin(dip2pxInt(10)) + .setGravity(Gravity.CENTER) + ) + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(dip2px(10)) + .setColor(color) + ); + container[0].addView(state); + + Column textContainer = new Column() + .setLayoutParams( + new LinearParams() + .setLeftMargin(dip2pxInt(10)) + .setRightMargin(dip2pxInt(10)) + .setGravity(Gravity.CENTER) + ); + container[0].addView(textContainer); + + Text title = new Text() + .setText(titleText) + .setTextSize(12f) + .setTextColor(hexColor("#E6E0E0E6")) + .setSingleLine(true); + textContainer.addView(title); + + Text description = new Text() + .setText(message) + .setTextSize(10f) + .setTextColor(hexColor("#B3A9A9B3")) + .setSingleLine(true); + textContainer.addView(description); + + if (column.build().getChildCount() > 0) { + if (column.build().getChildCount() * dip2pxInt(80) + dip2pxInt(80) > SystemH()) { + column.build().removeViewAt(0); + } + } + column.addView(container[0]); + return this; + } + + public Notification make(String titleText, String message) { + return make(titleText, message, Type.SUCCESS); + } + + // 新增的方法,用于支持中英文标题和消息 + public Notification make(String chineseTitle, String chineseMessage, String englishTitle, String englishMessage, Type type) { + // 检查语言切换文件并设置标题和消息 + String filePath = "/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; + File file = new File(filePath); + String displayTitle = file.exists() ? chineseTitle : englishTitle; + String displayMessage = file.exists() ? chineseMessage : englishMessage; + + final Row[] container = new Row[1]; + container[0] = new Row() + .setLayoutParams( + new LinearParams() + .setGravity(Gravity.RIGHT) + .setWidth(WrapContent) + .setHeight(dip2pxInt(50)) + .setAllMargins(dip2pxInt(10)) + ) + .setPadding(0, dip2pxInt(10), 0, dip2pxInt(10)) + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(dip2px(6)) + .setColor(hexColor("#B32C2C32")) + ) + .setElevation(dip2px(8)) + .postOnceDelayed(new PostCallback() { + + @Override + public void onPost(int width, int height) { + if (column.build().getChildCount() > 0) { + for (int i = 0; i < column.build().getChildCount(); i++) { + if (column.build().getChildAt(i) == container[0].build()) { + column.build().removeViewAt(i); + } + } + } + } + + }, Math.max(2500L * column.build().getChildCount(), 2500L)); + + int color; + if (type == Type.ERROR) { + color = hexColor("#CCFF5252"); + } else if (type == Type.WARN) { + color = hexColor("#CCFFB74D"); + } else { + color = hexColor("#CC66BB6A"); + } + + Widget state = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(dip2pxInt(10)) + .setHeight(dip2pxInt(10)) + .setLeftMargin(dip2pxInt(10)) + .setGravity(Gravity.CENTER) + ) + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(dip2px(10)) + .setColor(color) + ); + container[0].addView(state); + + Column textContainer = new Column() + .setLayoutParams( + new LinearParams() + .setLeftMargin(dip2pxInt(10)) + .setRightMargin(dip2pxInt(10)) + .setGravity(Gravity.CENTER) + ); + container[0].addView(textContainer); + + Text title = new Text() + .setText(displayTitle) + .setTextSize(12f) + .setTextColor(hexColor("#E6E0E0E6")) + .setSingleLine(true); + textContainer.addView(title); + + Text description = new Text() + .setText(displayMessage) + .setTextSize(10f) + .setTextColor(hexColor("#B3A9A9B3")) + .setSingleLine(true); + textContainer.addView(description); + + if (column.build().getChildCount() > 0) { + if (column.build().getChildCount() * dip2pxInt(80) + dip2pxInt(80) > SystemH()) { + column.build().removeViewAt(0); + } + } + column.addView(container[0]); + return this; + } + + public static enum Type { + SUCCESS, WARN, ERROR + } + + public static Notification getInstance() { + if (instance == null) { + instance = new Notification(); + } + return instance; + } +} diff --git a/app/src/main/java/com/bytecat/algui/effect/Notification.java.bak b/app/src/main/java/com/bytecat/algui/effect/Notification.java.bak new file mode 100644 index 0000000..0edcafc --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/Notification.java.bak @@ -0,0 +1,239 @@ +package com.bytecat.algui.effect; + +import android.animation.LayoutTransition; +import android.view.Gravity; +import android.view.View; + +import com.bytecat.algui.callback.PostCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.util.GradientDrawableBuilder; + +import java.io.File; + +public class Notification extends Popup { + + private Column column; + + private static Notification instance; + + public Notification() { + setWidth(MatchParent); + setHeight(MatchParent); + setFocusable(false); + setTouchable(false); + setGravity(Gravity.RIGHT | Gravity.BOTTOM); + setContentView(createContentView()); + } + + private Column createContentView() { + column = new Column() + .setGravity(Gravity.BOTTOM); + + LayoutTransition transition = new LayoutTransition(); + column.build().setLayoutTransition(transition); + return column; + } + + public Notification make(String titleText, String message, Type type) { + final Row[] container = new Row[1]; + container[0] = new Row() + .setLayoutParams( + new LinearParams() + .setGravity(Gravity.RIGHT) + .setWidth(WrapContent) + .setHeight(dip2pxInt(50)) + .setAllMargins(dip2pxInt(10)) + ) + .setPadding(0, dip2pxInt(10), 0, dip2pxInt(10)) + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(dip2px(6)) + .setColor(hexColor("#B32C2C32")) + ) + .setElevation(dip2px(8)) + .postOnceDelayed(new PostCallback() { + + @Override + public void onPost(int width, int height) { + if (column.build().getChildCount() > 0) { + for (int i = 0; i < column.build().getChildCount(); i++) { + if (column.build().getChildAt(i) == container[0].build()) { + column.build().removeViewAt(i); + } + } + } + } + + }, Math.max(2500L * column.build().getChildCount(), 2500L)); + + int color; + if (type == Type.ERROR) { + color = hexColor("#CCFF5252"); + } else if (type == Type.WARN) { + color = hexColor("#CCFFB74D"); + } else { + color = hexColor("#CC66BB6A"); + } + + Widget state = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(dip2pxInt(10)) + .setHeight(dip2pxInt(10)) + .setLeftMargin(dip2pxInt(10)) + .setGravity(Gravity.CENTER) + ) + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(dip2px(10)) + .setColor(color) + ); + container[0].addView(state); + + Column textContainer = new Column() + .setLayoutParams( + new LinearParams() + .setLeftMargin(dip2pxInt(10)) + .setRightMargin(dip2pxInt(10)) + .setGravity(Gravity.CENTER) + ); + container[0].addView(textContainer); + + Text title = new Text() + .setText(titleText) + .setTextSize(12f) + .setTextColor(hexColor("#E6E0E0E6")) + .setSingleLine(true); + textContainer.addView(title); + + Text description = new Text() + .setText(message) + .setTextSize(10f) + .setTextColor(hexColor("#B3A9A9B3")) + .setSingleLine(true); + textContainer.addView(description); + + if (column.build().getChildCount() > 0) { + if (column.build().getChildCount() * dip2pxInt(80) + dip2pxInt(80) > SystemH()) { + column.build().removeViewAt(0); + } + } + column.addView(container[0]); + return this; + } + + public Notification make(String titleText, String message) { + return make(titleText, message, Type.SUCCESS); + } + + // 新增的方法,用于支持中英文标题和消息 + public Notification make(String chineseTitle, String chineseMessage, String englishTitle, String englishMessage, Type type) { + // 检查语言切换文件并设置标题和消息 + String filePath = "/sdcard/Android/data/com.vortex.celestial/files/"; + File file = new File(filePath); + String displayTitle = file.exists() ? chineseTitle : englishTitle; + String displayMessage = file.exists() ? chineseMessage : englishMessage; + + final Row[] container = new Row[1]; + container[0] = new Row() + .setLayoutParams( + new LinearParams() + .setGravity(Gravity.RIGHT) + .setWidth(WrapContent) + .setHeight(dip2pxInt(50)) + .setAllMargins(dip2pxInt(10)) + ) + .setPadding(0, dip2pxInt(10), 0, dip2pxInt(10)) + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(dip2px(6)) + .setColor(hexColor("#B32C2C32")) + ) + .setElevation(dip2px(8)) + .postOnceDelayed(new PostCallback() { + + @Override + public void onPost(int width, int height) { + if (column.build().getChildCount() > 0) { + for (int i = 0; i < column.build().getChildCount(); i++) { + if (column.build().getChildAt(i) == container[0].build()) { + column.build().removeViewAt(i); + } + } + } + } + + }, Math.max(2500L * column.build().getChildCount(), 2500L)); + + int color; + if (type == Type.ERROR) { + color = hexColor("#CCFF5252"); + } else if (type == Type.WARN) { + color = hexColor("#CCFFB74D"); + } else { + color = hexColor("#CC66BB6A"); + } + + Widget state = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(dip2pxInt(10)) + .setHeight(dip2pxInt(10)) + .setLeftMargin(dip2pxInt(10)) + .setGravity(Gravity.CENTER) + ) + .setBackground( + new GradientDrawableBuilder() + .setAllRadius(dip2px(10)) + .setColor(color) + ); + container[0].addView(state); + + Column textContainer = new Column() + .setLayoutParams( + new LinearParams() + .setLeftMargin(dip2pxInt(10)) + .setRightMargin(dip2pxInt(10)) + .setGravity(Gravity.CENTER) + ); + container[0].addView(textContainer); + + Text title = new Text() + .setText(displayTitle) + .setTextSize(12f) + .setTextColor(hexColor("#E6E0E0E6")) + .setSingleLine(true); + textContainer.addView(title); + + Text description = new Text() + .setText(displayMessage) + .setTextSize(10f) + .setTextColor(hexColor("#B3A9A9B3")) + .setSingleLine(true); + textContainer.addView(description); + + if (column.build().getChildCount() > 0) { + if (column.build().getChildCount() * dip2pxInt(80) + dip2pxInt(80) > SystemH()) { + column.build().removeViewAt(0); + } + } + column.addView(container[0]); + return this; + } + + public static enum Type { + SUCCESS, WARN, ERROR + } + + public static Notification getInstance() { + if (instance == null) { + instance = new Notification(); + } + return instance; + } +} diff --git a/app/src/main/java/com/bytecat/algui/effect/ThemeManager.java b/app/src/main/java/com/bytecat/algui/effect/ThemeManager.java new file mode 100644 index 0000000..b7af7d4 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/effect/ThemeManager.java @@ -0,0 +1,53 @@ +package com.bytecat.algui.effect; + +import android.graphics.Color; +import java.util.ArrayList; +import java.util.List; + +public class ThemeManager { + private static ThemeManager instance; + private int themeColor = Color.parseColor("#00A8B5"); + private final List listeners = new ArrayList(); + + private ThemeManager() {} + + public static synchronized ThemeManager getInstance() { + if (instance == null) { + instance = new ThemeManager(); + } + return instance; + } + + public int getThemeColor() { + return themeColor; + } + + public void setThemeColor(int color) { + if (themeColor != color) { + themeColor = color; + notifyListeners(); + } + } + + public void addListener(OnThemeColorChangeListener listener) { + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + public void removeListener(OnThemeColorChangeListener listener) { + listeners.remove(listener); + } + + private void notifyListeners() { + for (OnThemeColorChangeListener l : listeners) { + if (l != null) { + l.onThemeColorChanged(themeColor); + } + } + } + + public interface OnThemeColorChangeListener { + void onThemeColorChanged(int newColor); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/handler/CrashHandler.java b/app/src/main/java/com/bytecat/algui/handler/CrashHandler.java new file mode 100644 index 0000000..3f76a14 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/handler/CrashHandler.java @@ -0,0 +1,54 @@ +package com.bytecat.algui.handler; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.os.Process; + +import com.bytecat.algui.CrashHandlerActivity; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +public class CrashHandler implements Thread.UncaughtExceptionHandler { + + private final Context context; + + private CrashHandler(Context context) { + this.context = context; + } + + @SuppressLint("StaticFieldLeak") + private static volatile CrashHandler instance; + + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + final StringWriter stringWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(stringWriter); + throwable.printStackTrace(printWriter); + final Intent intent = new Intent(context, CrashHandlerActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra("stackTrace", stringWriter.toString()); + try { + stringWriter.close(); + printWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + context.startActivity(intent); + Process.killProcess(Process.myPid()); + } + + public static void init(Context context) { + if (instance == null) { + synchronized (CrashHandler.class) { + if (instance == null) { + instance = new CrashHandler(context); + Thread.setDefaultUncaughtExceptionHandler(instance); + } + } + } + } + +} diff --git a/app/src/main/java/com/bytecat/algui/interpolator/FastOutSlowInInterpolator.java b/app/src/main/java/com/bytecat/algui/interpolator/FastOutSlowInInterpolator.java new file mode 100644 index 0000000..e015e6c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/interpolator/FastOutSlowInInterpolator.java @@ -0,0 +1,54 @@ +package com.bytecat.algui.interpolator; + +/** + * Interpolator corresponding to {@link android.R.interpolator#fast_out_slow_in}. + *

+ * Uses a lookup table for the Bezier curve from (0,0) to (1,1) with control points: + * P0 (0, 0) + * P1 (0.4, 0) + * P2 (0.2, 1.0) + * P3 (1.0, 1.0) + */ +public class FastOutSlowInInterpolator extends LookupTableInterpolator { + + /** + * Lookup table values sampled with x at regular intervals between 0 and 1 for a total of + * 201 points. + */ + private static final float[] VALUES = new float[]{ + 0.0000f, 0.0001f, 0.0002f, 0.0005f, 0.0009f, 0.0014f, 0.0020f, + 0.0027f, 0.0036f, 0.0046f, 0.0058f, 0.0071f, 0.0085f, 0.0101f, + 0.0118f, 0.0137f, 0.0158f, 0.0180f, 0.0205f, 0.0231f, 0.0259f, + 0.0289f, 0.0321f, 0.0355f, 0.0391f, 0.0430f, 0.0471f, 0.0514f, + 0.0560f, 0.0608f, 0.0660f, 0.0714f, 0.0771f, 0.0830f, 0.0893f, + 0.0959f, 0.1029f, 0.1101f, 0.1177f, 0.1257f, 0.1339f, 0.1426f, + 0.1516f, 0.1610f, 0.1707f, 0.1808f, 0.1913f, 0.2021f, 0.2133f, + 0.2248f, 0.2366f, 0.2487f, 0.2611f, 0.2738f, 0.2867f, 0.2998f, + 0.3131f, 0.3265f, 0.3400f, 0.3536f, 0.3673f, 0.3810f, 0.3946f, + 0.4082f, 0.4217f, 0.4352f, 0.4485f, 0.4616f, 0.4746f, 0.4874f, + 0.5000f, 0.5124f, 0.5246f, 0.5365f, 0.5482f, 0.5597f, 0.5710f, + 0.5820f, 0.5928f, 0.6033f, 0.6136f, 0.6237f, 0.6335f, 0.6431f, + 0.6525f, 0.6616f, 0.6706f, 0.6793f, 0.6878f, 0.6961f, 0.7043f, + 0.7122f, 0.7199f, 0.7275f, 0.7349f, 0.7421f, 0.7491f, 0.7559f, + 0.7626f, 0.7692f, 0.7756f, 0.7818f, 0.7879f, 0.7938f, 0.7996f, + 0.8053f, 0.8108f, 0.8162f, 0.8215f, 0.8266f, 0.8317f, 0.8366f, + 0.8414f, 0.8461f, 0.8507f, 0.8551f, 0.8595f, 0.8638f, 0.8679f, + 0.8720f, 0.8760f, 0.8798f, 0.8836f, 0.8873f, 0.8909f, 0.8945f, + 0.8979f, 0.9013f, 0.9046f, 0.9078f, 0.9109f, 0.9139f, 0.9169f, + 0.9198f, 0.9227f, 0.9254f, 0.9281f, 0.9307f, 0.9333f, 0.9358f, + 0.9382f, 0.9406f, 0.9429f, 0.9452f, 0.9474f, 0.9495f, 0.9516f, + 0.9536f, 0.9556f, 0.9575f, 0.9594f, 0.9612f, 0.9629f, 0.9646f, + 0.9663f, 0.9679f, 0.9695f, 0.9710f, 0.9725f, 0.9739f, 0.9753f, + 0.9766f, 0.9779f, 0.9791f, 0.9803f, 0.9815f, 0.9826f, 0.9837f, + 0.9848f, 0.9858f, 0.9867f, 0.9877f, 0.9885f, 0.9894f, 0.9902f, + 0.9910f, 0.9917f, 0.9924f, 0.9931f, 0.9937f, 0.9944f, 0.9949f, + 0.9955f, 0.9960f, 0.9964f, 0.9969f, 0.9973f, 0.9977f, 0.9980f, + 0.9984f, 0.9986f, 0.9989f, 0.9991f, 0.9993f, 0.9995f, 0.9997f, + 0.9998f, 0.9999f, 0.9999f, 1.0000f, 1.0000f + }; + + public FastOutSlowInInterpolator() { + super(VALUES); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/interpolator/LookupTableInterpolator.java b/app/src/main/java/com/bytecat/algui/interpolator/LookupTableInterpolator.java new file mode 100644 index 0000000..5889b5e --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/interpolator/LookupTableInterpolator.java @@ -0,0 +1,41 @@ +package com.bytecat.algui.interpolator; + +import android.view.animation.Interpolator; + +/** + * An {@link Interpolator} that uses a lookup table to compute an interpolation based on a + * given input. + */ +abstract class LookupTableInterpolator implements Interpolator { + + private final float[] mValues; + private final float mStepSize; + + public LookupTableInterpolator(float[] values) { + mValues = values; + mStepSize = 1f / (mValues.length - 1); + } + + @Override + public float getInterpolation(float input) { + if (input >= 1.0f) { + return 1.0f; + } + if (input <= 0f) { + return 0f; + } + + // Calculate index - We use min with length - 2 to avoid IndexOutOfBoundsException when + // we lerp (linearly interpolate) in the return statement + int position = Math.min((int) (input * (mValues.length - 1)), mValues.length - 2); + + // Calculate values to account for small offsets as the lookup table has discrete values + float quantized = position * mStepSize; + float diff = input - quantized; + float weight = diff / mStepSize; + + // Linearly interpolate between the table values + return mValues[position] + weight * (mValues[position + 1] - mValues[position]); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/layoutparams/BaseMarginLayoutParams.java b/app/src/main/java/com/bytecat/algui/layoutparams/BaseMarginLayoutParams.java new file mode 100644 index 0000000..4fe156f --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/layoutparams/BaseMarginLayoutParams.java @@ -0,0 +1,41 @@ +package com.bytecat.algui.layoutparams; + +import android.view.ViewGroup; + +import com.bytecat.algui.base.BaseHelper; + +public abstract class BaseMarginLayoutParams extends BaseParams { + + public T setAllMargins(int margins) { + return setMargins(margins, margins, margins, margins); + } + + public T setMargins(int left, int top, int right, int bottom) { + build().setMargins(left, top, right, bottom); + return (T) this; + } + + public T setLeftMargin(int left) { + build().leftMargin = left; + return (T) this; + } + + public T setTopMargin(int top) { + build().topMargin = top; + return (T) this; + } + + public T setRightMargin(int right) { + build().rightMargin = right; + return (T) this; + } + + public T setBottomMargin(int bottom) { + build().bottomMargin = bottom; + return (T) this; + } + + @Override + public abstract ViewGroup.MarginLayoutParams build(); + +} diff --git a/app/src/main/java/com/bytecat/algui/layoutparams/BaseParams.java b/app/src/main/java/com/bytecat/algui/layoutparams/BaseParams.java new file mode 100644 index 0000000..d2ca76a --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/layoutparams/BaseParams.java @@ -0,0 +1,21 @@ +package com.bytecat.algui.layoutparams; + +import android.view.ViewGroup; + +import com.bytecat.algui.base.BaseHelper; + +public abstract class BaseParams extends BaseHelper { + + public T setWidth(int width) { + build().width = width; + return (T) this; + } + + public T setHeight(int height) { + build().height = height; + return (T) this; + } + + public abstract ViewGroup.LayoutParams build(); + +} diff --git a/app/src/main/java/com/bytecat/algui/layoutparams/LinearParams.java b/app/src/main/java/com/bytecat/algui/layoutparams/LinearParams.java new file mode 100644 index 0000000..7094e16 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/layoutparams/LinearParams.java @@ -0,0 +1,29 @@ +package com.bytecat.algui.layoutparams; + +import android.view.ViewGroup; +import android.widget.LinearLayout; + +public class LinearParams extends BaseMarginLayoutParams { + + private final LinearLayout.LayoutParams layoutParams; + + public LinearParams() { + layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + } + + public LinearParams setGravity(int gravity) { + layoutParams.gravity = gravity; + return this; + } + + public LinearParams setWeight(float weight) { + layoutParams.weight = weight; + return this; + } + + @Override + public LinearLayout.LayoutParams build() { + return layoutParams; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/layoutparams/RelativeParams.java b/app/src/main/java/com/bytecat/algui/layoutparams/RelativeParams.java new file mode 100644 index 0000000..a015533 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/layoutparams/RelativeParams.java @@ -0,0 +1,43 @@ +package com.bytecat.algui.layoutparams; + +import android.view.ViewGroup; +import android.widget.RelativeLayout; + +public class RelativeParams extends BaseMarginLayoutParams { + + private final RelativeLayout.LayoutParams layoutParams; + + public RelativeParams() { + layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + } + + public RelativeParams alignWithParent() { + return alignWithParent(true); + } + + public RelativeParams alignWithParent(boolean enabled) { + build().alignWithParent = enabled; + return this; + } + + public RelativeParams addRule(int verb) { + build().addRule(verb); + return this; + } + + public RelativeParams addRule(int verb, int subject) { + build().addRule(verb, subject); + return this; + } + + public RelativeParams removeRule(int verb) { + build().removeRule(verb); + return this; + } + + @Override + public RelativeLayout.LayoutParams build() { + return layoutParams; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/layoutparams/StackParams.java b/app/src/main/java/com/bytecat/algui/layoutparams/StackParams.java new file mode 100644 index 0000000..0c13680 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/layoutparams/StackParams.java @@ -0,0 +1,24 @@ +package com.bytecat.algui.layoutparams; + +import android.view.ViewGroup; +import android.widget.FrameLayout; + +public class StackParams extends BaseMarginLayoutParams { + + private final FrameLayout.LayoutParams layoutParams; + + public StackParams() { + layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, WrapContent); + } + + public StackParams setGravity(int gravity) { + layoutParams.gravity = gravity; + return this; + } + + @Override + public ViewGroup.MarginLayoutParams build() { + return layoutParams; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/AlguiActivity.java b/app/src/main/java/com/bytecat/algui/ui/AlguiActivity.java new file mode 100644 index 0000000..6a0730f --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/AlguiActivity.java @@ -0,0 +1,39 @@ +package com.bytecat.algui.ui; + +import android.app.Activity; +import android.content.Intent; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiTools.AlguiToolPermission; + +public class AlguiActivity { + + private AlguiActivity() { + throw new UnsupportedOperationException("cannot be instantiated"); + } + + public static final String TAG = "AlguiActivity"; + public static Activity MainActivity; + + private static boolean isActivityWindow = false; + + public static void start(final Activity c) { + if (c != null) { + MainActivity = c; + AlguiLog.init(c); + if (isActivityWindow) { + Main.start(MainActivity); + } else { + AlguiToolPermission.getWindow(c, new AlguiToolPermission.PermissionCallback() { + public void run(boolean b) { + if (b) { + MainActivity.startService(new Intent(MainActivity, AlguiService.class)); + } else { + Main.start(MainActivity); + } + } + }); + } + } + } + } + diff --git a/app/src/main/java/com/bytecat/algui/ui/AlguiService.java b/app/src/main/java/com/bytecat/algui/ui/AlguiService.java new file mode 100644 index 0000000..624619c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/AlguiService.java @@ -0,0 +1,111 @@ +package com.bytecat.algui.ui; + +import android.app.Service; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.Typeface; +import android.os.IBinder; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.TextView; +import java.util.HashMap; +import java.util.Map; + +public class AlguiService extends Service { + + public static final String TAG = "AlguiService"; + private WindowManager windowManager; + private Map screenTexts = new HashMap<>(); + private static AlguiService instance; + + @Override + public void onCreate() { + super.onCreate(); + windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); + instance = this; + } + + @Override + public void onDestroy() { + super.onDestroy(); + clearAllScreenTexts(); + instance = null; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public static AlguiService getInstance() { + return instance; + } + + public void showScreenText(String text, String id, int x, int y, int textSize, float alpha) { + if (screenTexts.containsKey(id)) { + screenTexts.get(id).update(text, x, y, textSize, alpha); + } else { + TextView textView = new TextView(this); + textView.setText(text); + textView.setTextSize(textSize); + textView.setAlpha(alpha); + textView.setTextColor(Color.WHITE); + textView.setTypeface(Typeface.DEFAULT_BOLD); + textView.setGravity(Gravity.LEFT); + textView.setFocusable(false); + textView.setClickable(false); + textView.setLongClickable(false); + + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + params.x = x; + params.y = y; + params.gravity = Gravity.TOP | Gravity.START; + windowManager.addView(textView, params); + + ScreenText screenText = new ScreenText(textView, id); + screenTexts.put(id, screenText); + } + } + + public void removeScreenText(String id) { + if (screenTexts.containsKey(id)) { + ScreenText screenText = screenTexts.get(id); + windowManager.removeView(screenText.textView); + screenTexts.remove(id); + } + } + + public void clearAllScreenTexts() { + for (ScreenText screenText : screenTexts.values()) { + windowManager.removeView(screenText.textView); + } + screenTexts.clear(); + } + + private static class ScreenText { + private TextView textView; + private String id; + + public ScreenText(TextView textView, String id) { + this.textView = textView; + this.id = id; + } + + public void update(String text, int x, int y, int textSize, float alpha) { + textView.setText(text); + textView.setTextSize(textSize); + textView.setAlpha(alpha); + WindowManager.LayoutParams params = (WindowManager.LayoutParams) textView.getLayoutParams(); + params.x = x; + params.y = y; + textView.setLayoutParams(params); + } + } + } + diff --git a/app/src/main/java/com/bytecat/algui/ui/MIX.java b/app/src/main/java/com/bytecat/algui/ui/MIX.java new file mode 100644 index 0000000..db44f2b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/MIX.java @@ -0,0 +1,119 @@ +package com.bytecat.algui.ui; + +import android.app.Activity; +import android.os.Handler; +import android.os.Looper; + +import com.bytecat.algui.core.MuCuteUIX; +import com.bytecat.algui.effect.DynamicArrayList; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.ui.button.FloatButton; +import com.bytecat.algui.ace; +import android.content.Context; + +import com.bytecat.algui.effect.ArrayListView; +import com.bytecat.algui.effect.ModuleManager; + +/** @noinspection SpellCheckingInspection*/ +public final class MIX { + + private MIX() { + } + + public static boolean initialized; + + public static DynamicArrayList arrayList; + + public static ArrayListView arrayListView; + + public static Notification notification; + + public static FloatButton floatButton; + + private static Context context; + + public static void init() { + if (initialized) { + return; + } + + loop(); + loopThread(); + + + arrayListView = new ArrayListView (MIX.getContext()); + + arrayList = DynamicArrayList.getInstance(); + + + + + + + arrayList.show(); + + + + notification = Notification.getInstance(); + notification.show(); + + + floatButton = FloatButton.getInstance(); + floatButton.show(); + + initialized = true; + } + + private static void loop() { + new Handler(Looper.getMainLooper()).post(new Runnable() { + + /** @noinspection InfiniteLoopStatement*/ + @Override + public void run() { + while (true) { + try { + Looper.loop(); + } catch (Throwable e) { + e.printStackTrace(); + new Hint() + .setMessage("UI Loop Crash: " + e) + .show(); + } + } + } + + }); + } + + private static void loopThread() { + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, final Throwable e) { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + e.printStackTrace(); + new Hint() + .setMessage("Thread Loop Crash: " + e) + .show(); + } + }); + } + }); + } + + public static void init(Activity activity) { + ace.init(activity); + context=activity; + MuCuteUIX.init(activity); + init(); + + } + + public static Context getContext() { + return context; + } + + } + diff --git a/app/src/main/java/com/bytecat/algui/ui/Main.java b/app/src/main/java/com/bytecat/algui/ui/Main.java new file mode 100644 index 0000000..44ae410 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/Main.java @@ -0,0 +1,223 @@ +package com.bytecat.algui.ui; + +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.app.Activity; +import com.bytecat.algui.AlguiHacker.AlguiRootClient; +import com.bytecat.algui.AlguiHacker.AlguiRootService; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiManager.AlguiDocument; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import com.bytecat.algui.AlguiTools.AlguiToolNative; +import com.bytecat.algui.AlguiTools.AlguiToolNetwork; +import com.bytecat.algui.AlguiWindows.AlguiWin2FA; +import com.bytecat.algui.AlguiWindows.AlguiWinInform; +import com.bytecat.algui.MainActivity; +import com.bytecat.algui.effect.DynamicArrayList; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.ui.button.FloatButton; +import com.topjohnwu.superuser.ipc.RootService; +import java.util.HashMap; +import com.bytecat.algui.effect.ArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import android.os.Build; +import android.view.Gravity; +import com.bytecat.algui.AlguiViews.AlguiV; +import com.bytecat.algui.ui.category.RemoteLinkWatcher; +import com.bytecat.algui.effect.ModuleManager; +import android.text.TextUtils; + +public class Main { +public static boolean alreadyloggin; + public static boolean vt1 = true; + public static boolean vt2 = false; + public static boolean vt3 = false; +// 水印单例,全局可用 +public static AlguiV.TVNoSignalText tvNoSignal = null; + private static ExecutorService executor = Executors.newSingleThreadExecutor(); // 创建一个单线程线程池 + + public static void 音效播放() { + if (vt1) { + AlguiToolAudio.playAudio(aContext, "vt1.ogg"); + } + + if (vt2) { + AlguiToolAudio.playAudio(aContext, "vt2.ogg"); + } + + if (vt3) { + AlguiToolAudio.playAudio(aContext, "vt3.ogg"); + } + } + +public static void 音效() { + new Thread(new Runnable() { + @Override + public void run() { + 音效播放(); // 调用音效方法 + } + }).start(); +} + + + + + + + public static void 远控音效() { + AlguiToolAudio.playAudio(aContext, "cont.ogg"); + } +public static String km; + + // 内存修改示例 + public static boolean initialized; + + public static DynamicArrayList arrayList; + + public static Notification notification; + + public static FloatButton floatButton; + + // 网络验证 + private static boolean is2FA = true; + + private static Context aContext; // 确保 aContext 被正确声明 + + // 声明一个静态变量来保存当前活动 + public static Activity currentActivity; + + private static void Net2FA(final Activity currentActivity) { + AlguiWin2FA.Get(currentActivity, currentActivity) + .setCatWYAppID("57182") + .setCatWYAppCode("1.0") + .setCatWYOkCode(42589214) + .setCatWYAppKey("LL9EeZ8LResQ899i") + .setCatWYRC4_2("11L79sm1O5y57182") + .addRemoteFieldName("otone") + .addRemoteFieldName("ottwo") + .startWY(new AlguiCallback.WY2FA() { + + + public void success(String kami, String user, String vip, HashMap remote) { + } + + public void success(String kami, String expireTime, HashMap field) { + MyMenu(kami, expireTime, field, currentActivity); + } + }); + } + + private static void MyMenu(final String kami, final String expireTime, HashMap field, final Activity currentActivity) { + AlguiToolNative.loadLibrary("Algui"); + RootService.bind(new Intent(currentActivity, AlguiRootClient.class), new AlguiRootService()); + + String km = kami; + String time = expireTime; + String value1 = field.getOrDefault("otone", "这是远程变量获取失败时的默认值"); + String value2 = field.getOrDefault("ottwo", "这是远程变量获取失败时的默认值"); + final String markcode = android.os.Build.FINGERPRINT; + + new AsyncTask() { + @Override + protected String doInBackground(Void... voids) { + String codeList = AlguiToolNetwork.get(AlguiDocument.getRead("codeList")); + long count = 0; + if (codeList != null) { + for (int i = 0; i < codeList.length(); i++) { + if (codeList.charAt(i) == ';') { + count++; + } + } + } + if (codeList != null && !codeList.contains(markcode)) { + AlguiToolNetwork.get(AlguiDocument.getAdd("codeList", markcode + ";")); + count++; + + + + return "欢迎新用户!你是第" + count + "个用户"; + } + + return "全网人数:" + count; + } + + @Override + protected void onPostExecute(String result) { + AlguiToolAudio.playAudio(aContext, "oopen.ogg"); + +alreadyloggin = true; + +//远控 +RemoteLinkWatcher.startWatching( + "https://sharechain.qq.com/a3d3ef114852299548ab41773813c9bc", + "https://sharechain.qq.com/788e56aa9ad0ebb26f149c12c535e916", + MIX.getContext() +); + +final AlguiV a=AlguiV.Get(aContext);//获取UI快速构建器 + //绘制静态视图到屏幕上 + a.WinDraw + ( + a.TextTag(null, ""+ Build.BRAND + "\nAndroid" + Build.VERSION.RELEASE +"\nTrosCore v1.0.0", 0xCE000000, expireTime) + .setCatTextSize(8) + .setCatTextColor(0xFFFFFFFF) + ,//绘制的视图 + Gravity.BOTTOM | Gravity.START,//坐标原点 (这里右上原点) + 10, 10,//相对原点xy偏移 + false//视图是否可接收触摸事件 + ); + + final AlguiV.TVNoSignalText tvNoSignal = new AlguiV.TVNoSignalText(); +tvNoSignal.start("TrosCore\nAccount:"+kami); // 开 + + + + +// 初始化 MIX +MIX.init(currentActivity); + + + +String userName = TextUtils.isEmpty(AlguiWin2FA.wy_user) + ? "TrosCore用户" + : AlguiWin2FA.wy_user; + +ModuleManager.getInstance().setModuleEnabled( + "TrosCore", + true, + "Version:1.0.0 User:" + userName); + + + + + + } + }.execute(); + } + + private Main() { + throw new UnsupportedOperationException("cannot be instantiated"); + } + + public static final String TAG = "Main"; + + public static void start(Context c) { + aContext = c; + final Activity activity = (Activity) c; + currentActivity = activity; + activity.getWindow().getDecorView().postDelayed(new Runnable() { + @Override + public void run() { + if (is2FA) { + Net2FA(activity); + } else { + MyMenu("Free", "无限期", new HashMap(), activity); + } + } + }, 350L); + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/ScreenDrawer.java b/app/src/main/java/com/bytecat/algui/ui/ScreenDrawer.java new file mode 100644 index 0000000..29773a1 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/ScreenDrawer.java @@ -0,0 +1,107 @@ +package com.bytecat.algui.ui; + +import android.app.Activity; +import android.graphics.Color; +import android.graphics.Typeface; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import java.util.HashMap; +import java.util.Map; + +public class ScreenDrawer { + + private static Map screenTexts = new HashMap<>(); + + public static void addScreenText(Activity activity, String text, String id, int x, int y, int textSize, float alpha) { + if (activity == null) { + throw new IllegalStateException("Activity must not be null."); + } + + if (screenTexts.containsKey(id)) { + screenTexts.get(id).update(text, x, y, textSize, alpha); + } else { + ScreenText screenText = new ScreenText(activity, text, id, x, y, textSize, alpha); + screenTexts.put(id, screenText); + screenText.show(); + } + } + + public static void removeScreenText(Activity activity, String id) { + if (activity == null) { + throw new IllegalStateException("Activity must not be null."); + } + + if (screenTexts.containsKey(id)) { + screenTexts.get(id).hide(); + screenTexts.remove(id); + } + } + + public static void clearAllScreenTexts(Activity activity) { + if (activity == null) { + throw new IllegalStateException("Activity must not be null."); + } + + for (ScreenText screenText : screenTexts.values()) { + screenText.hide(); + } + screenTexts.clear(); + } + + private static class ScreenText extends TextView { + private String id; + private Activity activity; + + public ScreenText(Activity activity, String text, String id, int x, int y, int textSize, float alpha) { + super(activity); + this.activity = activity; + this.id = id; + setText(text); + setTextSize(textSize); + setAlpha(alpha); + setTextColor(Color.WHITE); + setTypeface(Typeface.DEFAULT_BOLD); + setGravity(Gravity.LEFT); + + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ); + params.leftMargin = x; + params.topMargin = y; + setLayoutParams(params); + + setFocusable(false); + setClickable(false); + setLongClickable(false); + } + + public void update(String text, int x, int y, int textSize, float alpha) { + setText(text); + setTextSize(textSize); + setAlpha(alpha); + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams(); + params.leftMargin = x; + params.topMargin = y; + setLayoutParams(params); + } + + public void show() { + if (getParent() == null && activity != null) { + ViewGroup rootView = (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content); + rootView.addView(this); + } + } + + public void hide() { + if (getParent() != null) { + ((ViewGroup) getParent()).removeView(this); + } + } + } + } + diff --git a/app/src/main/java/com/bytecat/algui/ui/button/FloatButton.java b/app/src/main/java/com/bytecat/algui/ui/button/FloatButton.java new file mode 100644 index 0000000..b72e2bb --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/button/FloatButton.java @@ -0,0 +1,205 @@ +package com.bytecat.algui.ui.button; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.drawable.GradientDrawable; +import android.os.Vibrator; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.effect.ClickFX; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.gui.ClickGUI; +import com.bytecat.algui.util.GradientDrawableBuilder; + +public class FloatButton extends Popup { + + private static FloatButton instance; + + public ClickGUI getClickGUI() { + return clickGUI; + } + + private ClickGUI clickGUI; + + private boolean openClickGUI; + + private int x, y; + + private float downX, downY, moveX, moveY; + + private static final float VECTOR = 0.15f; + + private boolean longClickDown; + + @SuppressLint("RtlHardcoded") + public FloatButton() { + x = SystemW() - dip2pxInt(60); + y = SystemH() / 2 - dip2pxInt(35 / 2); + + setWidth(dip2pxInt(33.5f)); + setHeight(dip2pxInt(33.5f)); + setContentView(createContentView()); + setGravity(Gravity.LEFT | Gravity.TOP); + setPosition(x, y); + setAnimation(Animation.Toast); + } + + public boolean isOpenClickGUI() { + return openClickGUI; + } + + public void openClickGUI() { + if (!isOpenClickGUI()) { + if (clickGUI == null) { + clickGUI = new ClickGUI(this); + } + clickGUI.show(); + + dismiss(); + openClickGUI = true; + } + } + + public void closeClickGUI() { + if (isOpenClickGUI()) { + clickGUI.dismiss(); + + show(); + openClickGUI = false; + } + } + + public int getCenterX() { + return x + dip2pxInt(17.5f); + } + + public int getCenterY() { + return y + dip2pxInt(15.5f); + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + private Column createContentView() { + final Column column = new Column() + .setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#FFFFFFFF")) + .setAllRadius(dip2px(35)) + ) + .setFocusable(true) + .setClickable(true) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + openClickGUI(); + } + }) + .setOnTouchListener(new View.OnTouchListener() { + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(View v, MotionEvent event) { + if (!longClickDown) { + downX = event.getX(); + downY = event.getY(); + return false; + } + + if (x > SystemW()) { + x = SystemW() - v.getWidth(); + } + + if (y > SystemH()) { + y = SystemH() - v.getHeight(); + } + + switch (event.getAction()) { + case MotionEvent.ACTION_MOVE: + float tempMoveX = (int) (event.getX() - downX) * VECTOR; + float tempMoveY = (int) (event.getY() - downY) * VECTOR; + if (x + tempMoveX + v.getWidth() > SystemW() || x + tempMoveX < 0) { + moveX = 0; + } else { + moveX = tempMoveX; + } + + if (y + tempMoveY + v.getHeight() > SystemH() || y + tempMoveY < 0) { + moveY = 0; + } else { + moveY = tempMoveY; + } + x = (int) (x + moveX); + y = (int) (y + moveY); + setPosition(x, y); + break; + case MotionEvent.ACTION_UP: + longClickDown = false; + break; + } + return false; + } + + }) + .setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + longClickDown = true; + Vibrator vibrator = (Vibrator) requireActivity().getSystemService(Context.VIBRATOR_SERVICE); + vibrator.vibrate(50L); + new ClickFX() + .show(x + v.getWidth() / 2, y + v.getHeight() / 2); + return true; + } + }); + + column.addView( + new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setAllMargins(dip2pxInt(6)) + ) + .setBackground( + new GradientDrawableBuilder() + .setColors(hexColor("#FFE66465"), hexColor("#FF9198E5")) + .setAllRadius(dip2px(25)) + .setOrientation(GradientDrawable.Orientation.BL_TR) + ) + .addView( + new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setAllMargins(dip2pxInt(5)) + ) + .setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#FFFFFFFF")) + .setAllRadius(dip2px(10)) + .setOrientation(GradientDrawable.Orientation.BR_TL) + ) + ) + ); + return column; + } + + public static FloatButton getInstance() { + if (instance == null) { + instance = new FloatButton(); + } + return instance; + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/button/RainbowAnimatorPool.java b/app/src/main/java/com/bytecat/algui/ui/button/RainbowAnimatorPool.java new file mode 100644 index 0000000..12f238e --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/button/RainbowAnimatorPool.java @@ -0,0 +1,71 @@ +package com.bytecat.algui.ui.button; + +import android.animation.ValueAnimator; +import android.graphics.drawable.Drawable; +import android.view.animation.LinearInterpolator; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public final class RainbowAnimatorPool { + private static RainbowAnimatorPool instance; + + private final ValueAnimator animator; + private final List> targets = + new ArrayList>(); + + /* 新增:无限递增的相位(角度) */ + private float cachedPhase = 0f; + + private RainbowAnimatorPool() { + // 每 2.5 秒转 360°,无限循环 + animator = ValueAnimator.ofFloat(0f, 360f); + animator.setDuration(5000); + animator.setRepeatCount(ValueAnimator.INFINITE); + animator.setInterpolator(new LinearInterpolator()); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + // 用模 360 仅给外部读,内部角度一直累加 + cachedPhase = (Float) animation.getAnimatedValue(); + synchronized (targets) { + Iterator> it = targets.iterator(); + while (it.hasNext()) { + Drawable d = it.next().get(); + if (d == null) { + it.remove(); + } else { + d.invalidateSelf(); + } + } + } + } + }); + } + + public static synchronized RainbowAnimatorPool getInstance() { + if (instance == null) instance = new RainbowAnimatorPool(); + return instance; + } + + public void register(Drawable drawable) { + if (targets.isEmpty()) animator.start(); + targets.add(new WeakReference(drawable)); + } + + public void unregister(Drawable drawable) { + Iterator> it = targets.iterator(); + while (it.hasNext()) { + Drawable d = it.next().get(); + if (d == null || d == drawable) it.remove(); + } + if (targets.isEmpty()) animator.cancel(); + } + + /* 无限递增相位(角度) */ + public float getPhase() { + return cachedPhase; + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/button/ShortcutButton.java b/app/src/main/java/com/bytecat/algui/ui/button/ShortcutButton.java new file mode 100644 index 0000000..6db3864 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/button/ShortcutButton.java @@ -0,0 +1,211 @@ +package com.bytecat.algui.ui.button; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Vibrator; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.PostCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.util.GradientDrawableBuilder; +import android.os.Handler; +import android.os.Looper; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.LinearGradient; +import android.graphics.Shader; +import android.graphics.Rect; +import android.graphics.Canvas; +import android.graphics.RectF; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.animation.ValueAnimator; +import android.view.animation.LinearInterpolator; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; + +public class ShortcutButton extends Popup { + + private int x, y; + + private float downX, downY, moveX, moveY; + + private static final float VECTOR = 0.15f; + + private boolean longClickDown; + + public Column textContainer; + + public Text text; + + /* ===== 中英文切换 ===== */ +private String chineseText; +private String englishText; +private String languageSwitchFilePath; + +public ShortcutButton OText(String chineseText, String englishText) { + this.chineseText = chineseText; + this.englishText = englishText; + updateTextBasedOnFile(); + return this; +} + + + +public ShortcutButton setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; +} + +private void updateTextBasedOnFile() { + if (languageSwitchFilePath == null) return; + boolean fileExists = new java.io.File(languageSwitchFilePath).exists(); + String target = fileExists ? chineseText : englishText; + if (target != null) setText(target); +} + + + + public ShortcutButton() { + x = SystemW() - dip2pxInt(200); + y = SystemH() / 2; + + setWidth(WrapContent); + setHeight(dip2pxInt(30)); + setAnimation(Animation.Toast); + setBackground( + new GradientDrawableBuilder() + .setAllRadius(20) + .setColor(hexColor("#B32C2C32")) + ); + setElevation(dip2px(2)); + setFocusable(false); + setContentView(createContentView()); + super.setPosition(x, y); + + } + + private Column createContentView() { + textContainer = new Column() + .setVisibility(View.GONE) + .setMinWidth(dip2pxInt(15)) + .setMinHeight(dip2pxInt(5)) + .setGravity(Gravity.CENTER) + .setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + longClickDown = true; + Vibrator vibrator = (Vibrator) requireActivity().getSystemService(Context.VIBRATOR_SERVICE); + vibrator.vibrate(50L); + return true; + } + }) + .setOnTouchListener(new View.OnTouchListener() { + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(View v, MotionEvent event) { + if (!longClickDown) { + downX = event.getX(); + downY = event.getY(); + return false; + } + + if (x > SystemW()) { + x = SystemW() - v.getWidth(); + } + + if (y > SystemH()) { + y = SystemH() - v.getHeight(); + } + + switch (event.getAction()) { + case MotionEvent.ACTION_MOVE: + float tempMoveX = (event.getX() - downX) * VECTOR; + float tempMoveY = (event.getY() - downY) * VECTOR; + if (x + tempMoveX + v.getWidth() > SystemW() || x + tempMoveX < 0) { + moveX = 0; + } else { + moveX = tempMoveX; + } + if (y + tempMoveY + v.getHeight() > SystemH() || y + tempMoveY < 0) { + moveY = 0; + } else { + moveY = tempMoveY; + } + x = (int) (x + moveX); + y = (int) (y + moveY); + setPosition(x, y); + break; + case MotionEvent.ACTION_UP: + longClickDown = false; + break; + } + + return false; + } + + }); + + text = new Text() + .setTextColor(hexColor("#B3E0E0E0")) + .setTextSize(dip2px(5.5f)) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setAllMargins(dip2pxInt(5)) + ); + textContainer.addView(text); + + return textContainer; + } + + public ShortcutButton setText(String content) { + if (content != null) { + textContainer.setVisibility(View.VISIBLE); + } + + textContainer.post(new PostCallback() { + @Override + public void onPost(int width, int height) { + setBackground( + new GradientDrawableBuilder() + + .setAllRadius(30) + .setColor(hexColor("#B32C2C32")) + .setStroke(2,hexColor("#9AFFFFFF")) + + ); + } + }); + text.setText(content); + return this; + } + + public ShortcutButton setOnClickListener(View.OnClickListener onClickListener) { + textContainer.setOnClickListener(onClickListener); + return this; + } + + @Override + public ShortcutButton setPosition(int x, int y) { + this.x = x; + this.y = y; + super.setPosition(x, y); + return this; + } + + private int safeColor(int value) { + return Math.max(Math.min(value, 255), 0); + }} +// 在ShortcutButton类中添加以下内部类 + diff --git a/app/src/main/java/com/bytecat/algui/ui/button/ShortcutButton.java.bak b/app/src/main/java/com/bytecat/algui/ui/button/ShortcutButton.java.bak new file mode 100644 index 0000000..cdb8ca1 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/button/ShortcutButton.java.bak @@ -0,0 +1,211 @@ +package com.bytecat.algui.ui.button; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Vibrator; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.PostCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.util.GradientDrawableBuilder; +import android.os.Handler; +import android.os.Looper; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.LinearGradient; +import android.graphics.Shader; +import android.graphics.Rect; +import android.graphics.Canvas; +import android.graphics.RectF; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.animation.ValueAnimator; +import android.view.animation.LinearInterpolator; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; + +public class ShortcutButton extends Popup { + + private int x, y; + + private float downX, downY, moveX, moveY; + + private static final float VECTOR = 0.15f; + + private boolean longClickDown; + + public Column textContainer; + + public Text text; + + /* ===== 中英文切换 ===== */ +private String chineseText; +private String englishText; +private String languageSwitchFilePath; + +public ShortcutButton OText(String chineseText, String englishText) { + this.chineseText = chineseText; + this.englishText = englishText; + updateTextBasedOnFile(); + return this; +} + + + +public ShortcutButton setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; +} + +private void updateTextBasedOnFile() { + if (languageSwitchFilePath == null) return; + boolean fileExists = new java.io.File(languageSwitchFilePath).exists(); + String target = fileExists ? chineseText : englishText; + if (target != null) setText(target); +} + + + + public ShortcutButton() { + x = SystemW() - dip2pxInt(200); + y = SystemH() / 2; + + setWidth(WrapContent); + setHeight(dip2pxInt(30)); + setAnimation(Animation.Toast); + setBackground( + new GradientDrawableBuilder() + .setAllRadius(20) + .setColor(hexColor("#B32C2C32")) + ); + setElevation(dip2px(2)); + setFocusable(false); + setContentView(createContentView()); + super.setPosition(x, y); + + } + + private Column createContentView() { + textContainer = new Column() + .setVisibility(View.GONE) + .setMinWidth(dip2pxInt(15)) + .setMinHeight(dip2pxInt(5)) + .setGravity(Gravity.CENTER) + .setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + longClickDown = true; + Vibrator vibrator = (Vibrator) requireActivity().getSystemService(Context.VIBRATOR_SERVICE); + vibrator.vibrate(50L); + return true; + } + }) + .setOnTouchListener(new View.OnTouchListener() { + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(View v, MotionEvent event) { + if (!longClickDown) { + downX = event.getX(); + downY = event.getY(); + return false; + } + + if (x > SystemW()) { + x = SystemW() - v.getWidth(); + } + + if (y > SystemH()) { + y = SystemH() - v.getHeight(); + } + + switch (event.getAction()) { + case MotionEvent.ACTION_MOVE: + float tempMoveX = (event.getX() - downX) * VECTOR; + float tempMoveY = (event.getY() - downY) * VECTOR; + if (x + tempMoveX + v.getWidth() > SystemW() || x + tempMoveX < 0) { + moveX = 0; + } else { + moveX = tempMoveX; + } + if (y + tempMoveY + v.getHeight() > SystemH() || y + tempMoveY < 0) { + moveY = 0; + } else { + moveY = tempMoveY; + } + x = (int) (x + moveX); + y = (int) (y + moveY); + setPosition(x, y); + break; + case MotionEvent.ACTION_UP: + longClickDown = false; + break; + } + + return false; + } + + }); + + text = new Text() + .setTextColor(hexColor("#B3E0E0E0")) + .setTextSize(16f) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setAllMargins(dip2pxInt(5)) + ); + textContainer.addView(text); + + return textContainer; + } + + public ShortcutButton setText(String content) { + if (content != null) { + textContainer.setVisibility(View.VISIBLE); + } + + textContainer.post(new PostCallback() { + @Override + public void onPost(int width, int height) { + setBackground( + new GradientDrawableBuilder() + + .setAllRadius(30) + .setColor(hexColor("#B32C2C32")) + .setStroke(2,hexColor("#9AFFFFFF")) + + ); + } + }); + text.setText(content); + return this; + } + + public ShortcutButton setOnClickListener(View.OnClickListener onClickListener) { + textContainer.setOnClickListener(onClickListener); + return this; + } + + @Override + public ShortcutButton setPosition(int x, int y) { + this.x = x; + this.y = y; + super.setPosition(x, y); + return this; + } + + private int safeColor(int value) { + return Math.max(Math.min(value, 255), 0); + }} +// 在ShortcutButton类中添加以下内部类 + diff --git a/app/src/main/java/com/bytecat/algui/ui/button/SwitchShortcutButton.java b/app/src/main/java/com/bytecat/algui/ui/button/SwitchShortcutButton.java new file mode 100644 index 0000000..1b64e22 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/button/SwitchShortcutButton.java @@ -0,0 +1,437 @@ +package com.bytecat.algui.ui.button; + +import android.animation.ValueAnimator; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +import com.bytecat.algui.animation.ValueAnimated; +import com.bytecat.algui.callback.SwitchCallback; +import android.os.Handler; +import android.os.Looper; +import android.graphics.Color; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.util.GradientDrawableBuilder; +import android.graphics.Shader; +import android.graphics.LinearGradient; +import android.widget.TextView; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.Drawable; +import com.bytecat.algui.effect.*; +import android.view.animation.*; +import android.animation.*; +import android.graphics.*; +import com.bytecat.algui.ui.button.SwitchShortcutButton.*; +import java.util.*; +import java.lang.ref.*; +import java.util.ArrayList; + +public class SwitchShortcutButton extends ShortcutButton { + + // 描边颜色与宽度 + // 保存背景 drawable,避免 getBackground() + private GradientDrawable backgroundDrawable; + private boolean isRainbow = false; + private boolean isRainbowEnabled = false; + private ValueAnimator rainbowAnimator; + private int baseThemeColor = ThemeManager.getInstance().getThemeColor(); + + private static boolean sRainbowEnabled = true; // 外部开关 + private RainbowStrokeTextDrawable rainbowStrokeTextDrawable; + + private String currentText = ""; // 保存当前文字 + // 兼容旧逻辑,可留空 +// 描边颜色 + private int colorStrokeOn = Color.parseColor("#FF7F7FD5"); + private int colorStrokeOff = Color.parseColor("#4DE0E0E0"); + + private int currentTextColor = Color.parseColor("#B3E0E0E0"); + +// 描边宽度(px) + // 描边宽度(px) + private static final int STROKE_WIDTH_ON = 1; // 开启时描边宽度 + private static final int STROKE_WIDTH_OFF = 1; // 关闭时描边宽度 + + // 外层描边(光晕) + private int colorGlowOn = Color.parseColor("#D9FFFFFF"); // 更亮的颜色 + private int colorGlowOff = Color.parseColor("#1AE0E0E0"); // 更淡的颜色 + + private static final int GLOW_WIDTH_ON = 8; // 外层光晕宽度 + private static final int GLOW_WIDTH_OFF = 0; // 关闭时不显示光晕 + + private GradientDrawable glowDrawable; // 外层光晕 + +// 当前描边宽度(动画用) + private int currentStrokeWidth = STROKE_WIDTH_OFF; + + public boolean isChecked; + + public ValueAnimated switchValueAnimated; + + private ValueAnimator textAnimator; // 用来控制文字彩虹 + private View.OnClickListener onClickListener; + + // 共享彩虹动画 + private float globalRainbowPhase = 0f; + private ValueAnimator globalRainbowAnimator; + + private SwitchCallback switchCallback; + + private static final String DEFAULT_LANGUAGE_SWITCH_FILE_PATH = "/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; + + /* ===== 中英文切换 ===== */ + + private String languageSwitchFilePath; + +private String chineseText; + private String englishText; + +/* 1. 【改动】把原来的常量路径改成下面这一行 */ + +/* 2. 【改动】把原来的 OText 方法删掉,换成下面这一段 */ +public SwitchShortcutButton OText(String chineseText, String englishText) { + this.chineseText = chineseText; + this.englishText = englishText; + // 直接调用原来的 updateTextBasedOnFile(),它会根据文件是否存在切换 + updateTextBasedOnFile(); + return this; +} + +/* 3. 【改动】把原来的 updateTextBasedOnFile 方法删掉,换成下面这一段 */ +private void updateTextBasedOnFile() { + String path = languageSwitchFilePath != null + ? languageSwitchFilePath + : DEFAULT_LANGUAGE_SWITCH_FILE_PATH; + boolean fileExists = new java.io.File(path).exists(); + String target = fileExists ? chineseText : englishText; + if (target != null) setText(target); +} + + private Drawable buildGlowBackgroundWithColor(int color) { + // 外层光晕 + GradientDrawable glow = new GradientDrawableBuilder() + .setAllRadius(32) + .setColor(Color.TRANSPARENT) + .setStroke(isChecked ? GLOW_WIDTH_ON : GLOW_WIDTH_OFF, color) + .build(); + + // 内层按钮 + GradientDrawable background = new GradientDrawableBuilder() + .setAllRadius(30) + .setColor(hexColor("#B32C2C32")) + .setStroke(isChecked ? STROKE_WIDTH_ON : STROKE_WIDTH_OFF, color) + .build(); + + LayerDrawable layer = new LayerDrawable(new Drawable[]{glow, background}); + int padding = 2; + layer.setLayerInset(0, 0, 0, 0, 0); + layer.setLayerInset(1, padding, padding, padding, padding); + return layer; + } + +public SwitchShortcutButton setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; +} + + + + public SwitchShortcutButton setStrokeColor(int onColor, int offColor) { + this.colorStrokeOn = onColor; + this.colorStrokeOff = offColor; + + return this; + } + + + + + + + public SwitchShortcutButton() { + this(false); + } + + public SwitchShortcutButton(boolean isChecked) { + this.isChecked = isChecked; + + // 创建并缓存背景 drawable + + // 内层按钮背景 + backgroundDrawable = new GradientDrawableBuilder() + .setAllRadius(30) // 内层圆角 + .setColor(hexColor("#B32C2C32")) + .setStroke(STROKE_WIDTH_OFF, colorStrokeOff) + .build(); + +// 外层光晕(圆角稍大) + + // ★替换原来的背景设置 + final int strokeColorTo = isChecked ? colorStrokeOn : colorStrokeOff; + + setBackground(buildGlowBackgroundWithColor(strokeColorTo)); // ✅ 拼写正确 + final + + + // 设置初始文字颜色 + text.setTextColor(hexColor(isChecked ? "#CC7F7FD5" : "#B3E0E0E0")); + + textContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (onClickListener != null) { + onClickListener.onClick(v); + } + if (switchCallback != null && + !switchCallback.onChecked(!SwitchShortcutButton.this.isChecked)) { + return; + } + animated(!SwitchShortcutButton.this.isChecked); + } + }); + } + + + + + + @Override + + public SwitchShortcutButton setText(String content) { + super.setText(content); + + this.currentText = content; + return this; + } + + public SwitchShortcutButton setChecked(boolean isChecked) { + if (this.isChecked != isChecked) { + animated(isChecked); + } + return this; + } + + +// 彩虹动画 + + +// 统一的背景构造 + + /** + * 全局彩虹开关 + * @param enable true 开启彩虹描边+文字;false 仅改变描边和文字颜色 + */ + + + + /** + * 全局彩虹开关 + * @param enable true 开启彩虹描边+文字;false 仅改变描边和文字颜色 + */ + public static void setRainbowEnabled(boolean enable) { + sRainbowEnabled = enable; + } + + public void onThemeColorChanged(int newColor) { + baseThemeColor = newColor; + if (!isRainbowEnabled) { + text.setTextColor(newColor); + setBackground(buildGlowBackgroundWithColor(newColor)); + } + } + + // 成员变量(放在类最上面) + + +// 动画主入口 + + private void startGlobalRainbowAnimation() { + if (globalRainbowAnimator != null) return; + + globalRainbowAnimator = ValueAnimator.ofFloat(0f, 360f); + globalRainbowAnimator.setDuration(5000); + globalRainbowAnimator.setRepeatCount(ValueAnimator.INFINITE); + globalRainbowAnimator.setInterpolator(new LinearInterpolator()); + globalRainbowAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + globalRainbowPhase = (Float) animation.getAnimatedValue(); + if (rainbowStrokeTextDrawable != null) rainbowStrokeTextDrawable.invalidateSelf(); + if (rainbowStrokeTextDrawable != null) rainbowStrokeTextDrawable.invalidateSelf(); + } + }); + globalRainbowAnimator.start(); + } + + private void stopGlobalRainbowAnimation() { + if (globalRainbowAnimator != null) { + globalRainbowAnimator.cancel(); + globalRainbowAnimator = null; + } + } + private void animated(final boolean isChecked) { + this.isChecked = isChecked; + + if (isChecked) { + if (sRainbowEnabled) { + text.setVisibility(View.INVISIBLE); // 隐藏原生 TextView + + // 关键:一个 Drawable 同时画描边 + 文字 + rainbowStrokeTextDrawable = new RainbowStrokeTextDrawable( + currentText, + dip2pxInt(STROKE_WIDTH_ON), + dip2px(12f)); + + LayerDrawable layers = new LayerDrawable(new Drawable[]{ + buildGlowBackgroundWithColor(Color.TRANSPARENT), + rainbowStrokeTextDrawable + }); + setBackground(layers); + } else { + text.setVisibility(View.VISIBLE); + setBackground(buildGlowBackgroundWithColor(colorStrokeOn)); + text.setTextColor(Color.parseColor("#CC7F7FD5")); + } + } else { + text.setVisibility(View.VISIBLE); + rainbowStrokeTextDrawable = null; + + setBackground(buildGlowBackgroundWithColor(colorStrokeOff)); + text.setTextColor(Color.parseColor("#B3E0E0E0")); + } + } + + /* ---------- 3. 彩虹动画 ---------- */ + + + /* ---------- 4. 带颜色的背景构造 ---------- */ + + + @Override + public SwitchShortcutButton setOnClickListener(View.OnClickListener onClickListener) { + this.onClickListener = onClickListener; + return this; + } + + public SwitchShortcutButton setSwicthCallback(SwitchCallback switchCallback) { + this.switchCallback = switchCallback; + return this; + } + + private int safeColor(int value) { + return Math.max(Math.min(value, 255), 0); + } + + + + /** + * 同时负责 彩虹描边 + 彩虹文字,二者共用同一个 Shader,保证完全同步。 + */ + /** + * 彩虹描边 + 彩虹文字,二者同步旋转,无分段 + */ + /** + * 彩虹描边 + 彩虹文字,左下角→右上角,白↔主题色流动 + * 直接覆盖原 RainbowStrokeTextDrawable 即可 + */ + private final class RainbowStrokeTextDrawable extends Drawable { + + private final Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final RectF roundRect = new RectF(); + private final String text; + private final float cornerRadius; + private final int strokeWidthPx; + + RainbowStrokeTextDrawable(String text, int strokeWidthPx, float cornerRadius) { + this.text = text; + this.strokeWidthPx = strokeWidthPx; + this.cornerRadius = cornerRadius; + + strokePaint.setStyle(Paint.Style.STROKE); + strokePaint.setStrokeWidth(strokeWidthPx); + strokePaint.setStrokeCap(Paint.Cap.ROUND); + + textPaint.setStyle(Paint.Style.FILL); + textPaint.setTextSize(dip2px(14)); + textPaint.setTextAlign(Paint.Align.CENTER); + + RainbowAnimatorPool.getInstance().register(this); + } + @Override + public void draw(Canvas canvas) { + float phase = RainbowAnimatorPool.getInstance().getPhase(); // 0→∞ + + roundRect.set(getBounds()); + roundRect.inset(strokeWidthPx / 2f, strokeWidthPx / 2f); + + float cx = getBounds().exactCenterX(); + float cy = getBounds().exactCenterY(); + + /* 1. 取当前主题色的 HSV 基准 */ + float[] hsv = new float[3]; + Color.colorToHSV(ThemeManager.getInstance().getThemeColor(), hsv); + + /* 2. 36 段彩虹,以主题色为起点,随 phase 连续旋转 */ + int steps = 36; + int[] colors = new int[steps + 1]; + float[] pos = new float[steps + 1]; + for (int i = 0; i <= steps; i++) { + float hue = (hsv[0] + phase + i * 360f / steps) % 360f; + colors[i] = Color.HSVToColor(new float[]{hue, hsv[1], hsv[2]}); + pos[i] = i / (float) steps; + } + + /* 3. SweepGradient 直接旋转色相环 */ + SweepGradient sweep = new SweepGradient(cx, cy, colors, pos); + + /* 4. 描边 */ + strokePaint.setShader(sweep); + strokePaint.setColorFilter(null); // 不再需要 ColorFilter + Path path = new Path(); + path.addRoundRect(roundRect, cornerRadius, cornerRadius, Path.Direction.CW); + canvas.drawPath(path, strokePaint); + + /* 5. 文字(同一 Shader)*/ + textPaint.setShader(sweep); + textPaint.setColorFilter(null); + canvas.drawText(text, cx, + cy - (textPaint.descent() + textPaint.ascent()) / 2f, textPaint); + } + + @Override protected void finalize() throws Throwable { + RainbowAnimatorPool.getInstance().unregister(this); + super.finalize(); + } + @Override public void setAlpha(int alpha) {} + @Override public void setColorFilter(ColorFilter cf) {} + @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } + } + + private static ColorFilter hueShift(float hue) { + float cos = (float) Math.cos(Math.toRadians(hue)); + float sin = (float) Math.sin(Math.toRadians(hue)); + + float[] mat = new float[]{ + // R 列 + 0.213f + cos * 0.787f - sin * 0.213f, + 0.715f - cos * 0.715f - sin * 0.715f, + 0.072f - cos * 0.072f + sin * 0.928f, 0, 0, + // G 列 + 0.213f - cos * 0.213f + sin * 0.143f, + 0.715f + cos * 0.285f + sin * 0.140f, + 0.072f - cos * 0.072f - sin * 0.283f, 0, 0, + // B 列 + 0.213f - cos * 0.213f - sin * 0.787f, + 0.715f - cos * 0.715f + sin * 0.715f, + 0.072f + cos * 0.928f + sin * 0.072f, 0, 0, + // A 列 + 0, 0, 0, 1, 0 + }; + return new ColorMatrixColorFilter(new ColorMatrix(mat)); + } + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/button/SwitchShortcutButton.java.bak b/app/src/main/java/com/bytecat/algui/ui/button/SwitchShortcutButton.java.bak new file mode 100644 index 0000000..4549700 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/button/SwitchShortcutButton.java.bak @@ -0,0 +1,437 @@ +package com.bytecat.algui.ui.button; + +import android.animation.ValueAnimator; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +import com.bytecat.algui.animation.ValueAnimated; +import com.bytecat.algui.callback.SwitchCallback; +import android.os.Handler; +import android.os.Looper; +import android.graphics.Color; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.util.GradientDrawableBuilder; +import android.graphics.Shader; +import android.graphics.LinearGradient; +import android.widget.TextView; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.Drawable; +import com.bytecat.algui.effect.*; +import android.view.animation.*; +import android.animation.*; +import android.graphics.*; +import com.bytecat.algui.ui.button.SwitchShortcutButton.*; +import java.util.*; +import java.lang.ref.*; +import java.util.ArrayList; + +public class SwitchShortcutButton extends ShortcutButton { + + // 描边颜色与宽度 + // 保存背景 drawable,避免 getBackground() + private GradientDrawable backgroundDrawable; + private boolean isRainbow = false; + private boolean isRainbowEnabled = false; + private ValueAnimator rainbowAnimator; + private int baseThemeColor = ThemeManager.getInstance().getThemeColor(); + + private static boolean sRainbowEnabled = true; // 外部开关 + private RainbowStrokeTextDrawable rainbowStrokeTextDrawable; + + private String currentText = ""; // 保存当前文字 + // 兼容旧逻辑,可留空 +// 描边颜色 + private int colorStrokeOn = Color.parseColor("#FF7F7FD5"); + private int colorStrokeOff = Color.parseColor("#4DE0E0E0"); + + private int currentTextColor = Color.parseColor("#B3E0E0E0"); + +// 描边宽度(px) + // 描边宽度(px) + private static final int STROKE_WIDTH_ON = 1; // 开启时描边宽度 + private static final int STROKE_WIDTH_OFF = 1; // 关闭时描边宽度 + + // 外层描边(光晕) + private int colorGlowOn = Color.parseColor("#D9FFFFFF"); // 更亮的颜色 + private int colorGlowOff = Color.parseColor("#1AE0E0E0"); // 更淡的颜色 + + private static final int GLOW_WIDTH_ON = 8; // 外层光晕宽度 + private static final int GLOW_WIDTH_OFF = 0; // 关闭时不显示光晕 + + private GradientDrawable glowDrawable; // 外层光晕 + +// 当前描边宽度(动画用) + private int currentStrokeWidth = STROKE_WIDTH_OFF; + + public boolean isChecked; + + public ValueAnimated switchValueAnimated; + + private ValueAnimator textAnimator; // 用来控制文字彩虹 + private View.OnClickListener onClickListener; + + // 共享彩虹动画 + private float globalRainbowPhase = 0f; + private ValueAnimator globalRainbowAnimator; + + private SwitchCallback switchCallback; + + private static final String DEFAULT_LANGUAGE_SWITCH_FILE_PATH = "/sdcard/TC配置文件/switch.lang"; + + /* ===== 中英文切换 ===== */ + + private String languageSwitchFilePath; + +private String chineseText; + private String englishText; + +/* 1. 【改动】把原来的常量路径改成下面这一行 */ + +/* 2. 【改动】把原来的 OText 方法删掉,换成下面这一段 */ +public SwitchShortcutButton OText(String chineseText, String englishText) { + this.chineseText = chineseText; + this.englishText = englishText; + // 直接调用原来的 updateTextBasedOnFile(),它会根据文件是否存在切换 + updateTextBasedOnFile(); + return this; +} + +/* 3. 【改动】把原来的 updateTextBasedOnFile 方法删掉,换成下面这一段 */ +private void updateTextBasedOnFile() { + String path = languageSwitchFilePath != null + ? languageSwitchFilePath + : DEFAULT_LANGUAGE_SWITCH_FILE_PATH; + boolean fileExists = new java.io.File(path).exists(); + String target = fileExists ? chineseText : englishText; + if (target != null) setText(target); +} + + private Drawable buildGlowBackgroundWithColor(int color) { + // 外层光晕 + GradientDrawable glow = new GradientDrawableBuilder() + .setAllRadius(32) + .setColor(Color.TRANSPARENT) + .setStroke(isChecked ? GLOW_WIDTH_ON : GLOW_WIDTH_OFF, color) + .build(); + + // 内层按钮 + GradientDrawable background = new GradientDrawableBuilder() + .setAllRadius(30) + .setColor(hexColor("#B32C2C32")) + .setStroke(isChecked ? STROKE_WIDTH_ON : STROKE_WIDTH_OFF, color) + .build(); + + LayerDrawable layer = new LayerDrawable(new Drawable[]{glow, background}); + int padding = 2; + layer.setLayerInset(0, 0, 0, 0, 0); + layer.setLayerInset(1, padding, padding, padding, padding); + return layer; + } + +public SwitchShortcutButton setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; +} + + + + public SwitchShortcutButton setStrokeColor(int onColor, int offColor) { + this.colorStrokeOn = onColor; + this.colorStrokeOff = offColor; + + return this; + } + + + + + + + public SwitchShortcutButton() { + this(false); + } + + public SwitchShortcutButton(boolean isChecked) { + this.isChecked = isChecked; + + // 创建并缓存背景 drawable + + // 内层按钮背景 + backgroundDrawable = new GradientDrawableBuilder() + .setAllRadius(30) // 内层圆角 + .setColor(hexColor("#B32C2C32")) + .setStroke(STROKE_WIDTH_OFF, colorStrokeOff) + .build(); + +// 外层光晕(圆角稍大) + + // ★替换原来的背景设置 + final int strokeColorTo = isChecked ? colorStrokeOn : colorStrokeOff; + + setBackground(buildGlowBackgroundWithColor(strokeColorTo)); // ✅ 拼写正确 + final + + + // 设置初始文字颜色 + text.setTextColor(hexColor(isChecked ? "#CC7F7FD5" : "#B3E0E0E0")); + + textContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (onClickListener != null) { + onClickListener.onClick(v); + } + if (switchCallback != null && + !switchCallback.onChecked(!SwitchShortcutButton.this.isChecked)) { + return; + } + animated(!SwitchShortcutButton.this.isChecked); + } + }); + } + + + + + + @Override + + public SwitchShortcutButton setText(String content) { + super.setText(content); + + this.currentText = content; + return this; + } + + public SwitchShortcutButton setChecked(boolean isChecked) { + if (this.isChecked != isChecked) { + animated(isChecked); + } + return this; + } + + +// 彩虹动画 + + +// 统一的背景构造 + + /** + * 全局彩虹开关 + * @param enable true 开启彩虹描边+文字;false 仅改变描边和文字颜色 + */ + + + + /** + * 全局彩虹开关 + * @param enable true 开启彩虹描边+文字;false 仅改变描边和文字颜色 + */ + public static void setRainbowEnabled(boolean enable) { + sRainbowEnabled = enable; + } + + public void onThemeColorChanged(int newColor) { + baseThemeColor = newColor; + if (!isRainbowEnabled) { + text.setTextColor(newColor); + setBackground(buildGlowBackgroundWithColor(newColor)); + } + } + + // 成员变量(放在类最上面) + + +// 动画主入口 + + private void startGlobalRainbowAnimation() { + if (globalRainbowAnimator != null) return; + + globalRainbowAnimator = ValueAnimator.ofFloat(0f, 360f); + globalRainbowAnimator.setDuration(5000); + globalRainbowAnimator.setRepeatCount(ValueAnimator.INFINITE); + globalRainbowAnimator.setInterpolator(new LinearInterpolator()); + globalRainbowAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + globalRainbowPhase = (Float) animation.getAnimatedValue(); + if (rainbowStrokeTextDrawable != null) rainbowStrokeTextDrawable.invalidateSelf(); + if (rainbowStrokeTextDrawable != null) rainbowStrokeTextDrawable.invalidateSelf(); + } + }); + globalRainbowAnimator.start(); + } + + private void stopGlobalRainbowAnimation() { + if (globalRainbowAnimator != null) { + globalRainbowAnimator.cancel(); + globalRainbowAnimator = null; + } + } + private void animated(final boolean isChecked) { + this.isChecked = isChecked; + + if (isChecked) { + if (sRainbowEnabled) { + text.setVisibility(View.INVISIBLE); // 隐藏原生 TextView + + // 关键:一个 Drawable 同时画描边 + 文字 + rainbowStrokeTextDrawable = new RainbowStrokeTextDrawable( + currentText, + dip2pxInt(STROKE_WIDTH_ON), + dip2px(12f)); + + LayerDrawable layers = new LayerDrawable(new Drawable[]{ + buildGlowBackgroundWithColor(Color.TRANSPARENT), + rainbowStrokeTextDrawable + }); + setBackground(layers); + } else { + text.setVisibility(View.VISIBLE); + setBackground(buildGlowBackgroundWithColor(colorStrokeOn)); + text.setTextColor(Color.parseColor("#CC7F7FD5")); + } + } else { + text.setVisibility(View.VISIBLE); + rainbowStrokeTextDrawable = null; + + setBackground(buildGlowBackgroundWithColor(colorStrokeOff)); + text.setTextColor(Color.parseColor("#B3E0E0E0")); + } + } + + /* ---------- 3. 彩虹动画 ---------- */ + + + /* ---------- 4. 带颜色的背景构造 ---------- */ + + + @Override + public SwitchShortcutButton setOnClickListener(View.OnClickListener onClickListener) { + this.onClickListener = onClickListener; + return this; + } + + public SwitchShortcutButton setSwicthCallback(SwitchCallback switchCallback) { + this.switchCallback = switchCallback; + return this; + } + + private int safeColor(int value) { + return Math.max(Math.min(value, 255), 0); + } + + + + /** + * 同时负责 彩虹描边 + 彩虹文字,二者共用同一个 Shader,保证完全同步。 + */ + /** + * 彩虹描边 + 彩虹文字,二者同步旋转,无分段 + */ + /** + * 彩虹描边 + 彩虹文字,左下角→右上角,白↔主题色流动 + * 直接覆盖原 RainbowStrokeTextDrawable 即可 + */ + private final class RainbowStrokeTextDrawable extends Drawable { + + private final Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final RectF roundRect = new RectF(); + private final String text; + private final float cornerRadius; + private final int strokeWidthPx; + + RainbowStrokeTextDrawable(String text, int strokeWidthPx, float cornerRadius) { + this.text = text; + this.strokeWidthPx = strokeWidthPx; + this.cornerRadius = cornerRadius; + + strokePaint.setStyle(Paint.Style.STROKE); + strokePaint.setStrokeWidth(strokeWidthPx); + strokePaint.setStrokeCap(Paint.Cap.ROUND); + + textPaint.setStyle(Paint.Style.FILL); + textPaint.setTextSize(dip2px(14)); + textPaint.setTextAlign(Paint.Align.CENTER); + + RainbowAnimatorPool.getInstance().register(this); + } + @Override + public void draw(Canvas canvas) { + float phase = RainbowAnimatorPool.getInstance().getPhase(); // 0→∞ + + roundRect.set(getBounds()); + roundRect.inset(strokeWidthPx / 2f, strokeWidthPx / 2f); + + float cx = getBounds().exactCenterX(); + float cy = getBounds().exactCenterY(); + + /* 1. 取当前主题色的 HSV 基准 */ + float[] hsv = new float[3]; + Color.colorToHSV(ThemeManager.getInstance().getThemeColor(), hsv); + + /* 2. 36 段彩虹,以主题色为起点,随 phase 连续旋转 */ + int steps = 36; + int[] colors = new int[steps + 1]; + float[] pos = new float[steps + 1]; + for (int i = 0; i <= steps; i++) { + float hue = (hsv[0] + phase + i * 360f / steps) % 360f; + colors[i] = Color.HSVToColor(new float[]{hue, hsv[1], hsv[2]}); + pos[i] = i / (float) steps; + } + + /* 3. SweepGradient 直接旋转色相环 */ + SweepGradient sweep = new SweepGradient(cx, cy, colors, pos); + + /* 4. 描边 */ + strokePaint.setShader(sweep); + strokePaint.setColorFilter(null); // 不再需要 ColorFilter + Path path = new Path(); + path.addRoundRect(roundRect, cornerRadius, cornerRadius, Path.Direction.CW); + canvas.drawPath(path, strokePaint); + + /* 5. 文字(同一 Shader)*/ + textPaint.setShader(sweep); + textPaint.setColorFilter(null); + canvas.drawText(text, cx, + cy - (textPaint.descent() + textPaint.ascent()) / 2f, textPaint); + } + + @Override protected void finalize() throws Throwable { + RainbowAnimatorPool.getInstance().unregister(this); + super.finalize(); + } + @Override public void setAlpha(int alpha) {} + @Override public void setColorFilter(ColorFilter cf) {} + @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } + } + + private static ColorFilter hueShift(float hue) { + float cos = (float) Math.cos(Math.toRadians(hue)); + float sin = (float) Math.sin(Math.toRadians(hue)); + + float[] mat = new float[]{ + // R 列 + 0.213f + cos * 0.787f - sin * 0.213f, + 0.715f - cos * 0.715f - sin * 0.715f, + 0.072f - cos * 0.072f + sin * 0.928f, 0, 0, + // G 列 + 0.213f - cos * 0.213f + sin * 0.143f, + 0.715f + cos * 0.285f + sin * 0.140f, + 0.072f - cos * 0.072f - sin * 0.283f, 0, 0, + // B 列 + 0.213f - cos * 0.213f - sin * 0.787f, + 0.715f - cos * 0.715f + sin * 0.715f, + 0.072f + cos * 0.928f + sin * 0.072f, 0, 0, + // A 列 + 0, 0, 0, 1, 0 + }; + return new ColorMatrixColorFilter(new ColorMatrix(mat)); + } + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/button/kuai.java b/app/src/main/java/com/bytecat/algui/ui/button/kuai.java new file mode 100644 index 0000000..8c1d5eb --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/button/kuai.java @@ -0,0 +1,232 @@ +package com.bytecat.algui.ui.button; + + +import android.content.Context; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.FrameLayout; +import android.widget.SeekBar; +import com.bytecat.algui.ui.MIX; +import android.widget.TextView; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.LayerDrawable; + + +public class kuai { + //GitHub https + public static int c; + + + + private WindowManager windowManager; + + + public kuai() { + // 使用 MIX.getContext() 获取上下文 + Context context = MIX.getContext(); + if (context == null) { + throw new IllegalStateException("MIX context is not initialized. Call MIX.init() first."); + } + + + + } + + /** + * 创建一个可拖动的悬浮 SeekBar + * + * @param 上下文 上下文对象 + * @param 改变监听 SeekBar 的进度变化监听器(可为 null) + * @return 添加到 WindowManager 后的 SeekBar 对象 + */ + public SeekBar 创建悬浮SeekBar(Context 上下文, String 文字, final SeekBar.OnSeekBarChangeListener 改变监听) { + windowManager = (WindowManager) 上下文.getSystemService(Context.WINDOW_SERVICE); + final AlguiViewText djdj= new AlguiViewText(上下文); + djdj.setText(文字); + djdj.setTextColor(0xFF000000); + djdj.setTextSize(15); + djdj.setCatTextGravity(3); + djdj.setCatMargins(10,0,10,0); + + djdj.setGravity(Gravity.CENTER); // 文本居中对齐 + + // 创建父容器(宽度150dp,背景淡灰色,圆角8dp,阴影效果) + FrameLayout container = new FrameLayout(上下文); + GradientDrawable backgroundDrawable = new GradientDrawable(); + backgroundDrawable.setColor(Color.parseColor("#F0F0F0")); // 背景颜色为淡灰色 + backgroundDrawable.setCornerRadius(dp2px(上下文, 8)); // 设置圆角大小为8dp + backgroundDrawable.setStroke(dp2px(上下文, 1), Color.parseColor("#808080")); // 设置灰色描边,宽度1dp + backgroundDrawable.setPadding(dp2px(上下文, 4), dp2px(上下文, 4), dp2px(上下文, 4), dp2px(上下文, 4)); // 添加内边距 + container.setBackground(backgroundDrawable); + + int containerWidth = dp2px(上下文, 150); + int containerHeight = dp2px(上下文, 40); + container.setLayoutParams(new FrameLayout.LayoutParams(containerWidth, containerHeight)); + + // 添加文本标签到父容器 + FrameLayout.LayoutParams textParams = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT, + Gravity.CENTER_VERTICAL | Gravity.LEFT // 文本居中且靠左 + ); + textParams.leftMargin = dp2px(上下文, 10); // 文本左边距为10dp + textParams.rightMargin = dp2px(上下文, 10); // 文本左边距为10dp + container.addView(djdj, textParams); + + // 创建SeekBar(宽度100dp,右侧对齐) + final SeekBar seekBar = new SeekBar(上下文); + seekBar.setMax(20000); + seekBar.setMin(-100); + + // 设置SeekBar的进度条颜色和拇指颜色 + + FrameLayout.LayoutParams seekBarParams = new FrameLayout.LayoutParams( + dp2px(上下文, 100), + FrameLayout.LayoutParams.MATCH_PARENT, + Gravity.CENTER_VERTICAL | Gravity.RIGHT // SeekBar居中且靠右 + ); + seekBarParams.rightMargin = dp2px(上下文, 10); // SeekBar右边距为10dp + seekBarParams.leftMargin = dp2px(上下文, 30); // 增加SeekBar的左边距,使其与文本标签隔开 + container.addView(seekBar, seekBarParams); + + + final WindowManager.LayoutParams 布局参数 = 创建默认布局参数(); + 布局参数.width = containerWidth; + 布局参数.height = containerHeight; + + + + + // 创建SeekBar(宽度100dp,右侧对齐) + + + + // 将拖动事件绑定到父容器(保持原逻辑) + 绑定拖动事件1(container, 布局参数); + + windowManager.addView(container, 布局参数); + + + if (改变监听 != null) { + seekBar.setOnSeekBarChangeListener(改变监听); + } + + return seekBar; + } + + + + + /* 其余方法(dp2px、绑定拖动事件1)保持不变 */ + + + /** + * dp 转换为 px 的工具方法 + */ + private int dp2px(Context context, float dp) { + return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f); + } + + /** + * 新的绑定拖动事件1方法,使悬浮视图可拖动,同时保留内部控件(例如 SeekBar)的触摸功能 + */ + private void 绑定拖动事件1(final View 视图, final WindowManager.LayoutParams 布局参数) { + 视图.setOnTouchListener(new View.OnTouchListener() { + private int 初始X, 初始Y; + private float 初始触摸X, 初始触摸Y; + private boolean isDragging = false; + private boolean isLongPressed = false; + private final int DRAG_THRESHOLD = 10; + private final int LONG_PRESS_TIME = 0; // 0.5 秒 + private android.os.Handler handler = new android.os.Handler(); + private Runnable longPressRunnable = new Runnable() { + @Override + public void run() { + isLongPressed = true; + } + }; + + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + 初始X = 布局参数.x; + 初始Y = 布局参数.y; + 初始触摸X = event.getRawX(); + 初始触摸Y = event.getRawY(); + isDragging = false; + isLongPressed = false; + handler.postDelayed(longPressRunnable, LONG_PRESS_TIME); + return false; + case MotionEvent.ACTION_MOVE: + float dx = event.getRawX() - 初始触摸X; + float dy = event.getRawY() - 初始触摸Y; + + if (isLongPressed && !isDragging && (Math.abs(dx) > DRAG_THRESHOLD || Math.abs(dy) > DRAG_THRESHOLD)) { + isDragging = true; + } + + if (isDragging) { + 布局参数.x = 初始X + (int) dx; + 布局参数.y = 初始Y + (int) dy; + windowManager.updateViewLayout(视图, 布局参数); + return true; + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + handler.removeCallbacks(longPressRunnable); + if (isDragging) { + return true; + } + break; + } + return false; + } + }); + } + + + + + /** + * 创建默认的 WindowManager 布局参数 + */ + private WindowManager.LayoutParams 创建默认布局参数() { + return new WindowManager.LayoutParams( + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + 0, // initialX + 0, // initialY + WindowManager.LayoutParams.TYPE_APPLICATION, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE & ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | + WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN | + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.RGBA_8888 + ); + } + + public void 关闭(View 名称) { + if (windowManager != null && 名称 != null) { + windowManager.removeView(名称); + } + } + + /** + * 绑定拖动事件,使悬浮窗可拖动 + */ + +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/ui/category/AttackCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/AttackCategoryBox.java new file mode 100644 index 0000000..e5779c7 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/AttackCategoryBox.java @@ -0,0 +1,2594 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.graphics.Typeface; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.effect.Hint; +import java.security.Identity; +import com.bytecat.algui.ace; +import android.content.Context; +import android.app.Activity; +import java.lang.ref.WeakReference; +import irene.window.algui.Tools.HackerTool; +import irene.window.algui.MainActivity; +import java.util.concurrent.ConcurrentHashMap; +import java.io.InputStream; +import java.io.File; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import irene.window.algui.AlGuiBubbleNotification; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.bytecat.algui.ui.component.Button; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.callback.ClickCallback; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.ArrayList; +import android.os.Handler; +import com.bytecat.algui.AlguiWindows.AlguiWinInform; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import android.graphics.Paint; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import android.graphics.Canvas; +import android.view.SurfaceHolder; +import android.os.Looper; +import java.util.List; +import java.util.Map; +import java.util.Collections; +import android.view.WindowManager; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import android.graphics.Path; +import java.util.concurrent.TimeUnit; +import com.bytecat.algui.AlguiWindows.AlguiWinDraw; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.component.BoxContentCard; +import java.util.concurrent.CopyOnWriteArrayList; +import android.os.AsyncTask; +import com.bytecat.algui.effect.ArrayListView; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.effect.ColorPickerPopup; + +public class AttackCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + private ClickCallback clickCallback; + + private static final ConcurrentHashMap runningProcesses = new ConcurrentHashMap<>(); + + public static void executeHiddenBinary(Context context, String assetFileName) { + Process existingProcess = runningProcesses.get(assetFileName); + if (existingProcess != null && existingProcess.isAlive()) { + existingProcess.destroy(); + } + runningProcesses.remove(assetFileName); + try { + InputStream is = context.getAssets().open(assetFileName); + File tempFile = File.createTempFile("bin_", null, context.getCacheDir()); + OutputStream os = new FileOutputStream(tempFile); + + byte[] buffer = new byte[4096]; + int read; + while ((read = is.read(buffer)) != -1) { + os.write(buffer, 0, read); + } + is.close(); + os.close(); + + Runtime.getRuntime().exec("chmod 777 " + tempFile.getAbsolutePath()).waitFor(); + + Process process = Runtime.getRuntime().exec(tempFile.getAbsolutePath()); + runningProcesses.put(assetFileName, process); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } + + public static void stopBinary(String assetFileName) { + Process process = runningProcesses.get(assetFileName); + if (process != null && process.isAlive()) { + process.destroy(); + } + runningProcesses.remove(assetFileName); + } + + + + private static WeakReference contextRef = new WeakReference<>(null); + + public static void init(Context context) { + contextRef = new WeakReference<>(context.getApplicationContext()); + } + + // 保留原有的标志变量 + + public static boolean condition = true; + public static boolean xhfw = true; // 保留原有的xhfw循环标志 + private static Thread loopThread; + private static final AtomicBoolean isInitialized = new AtomicBoolean(false); +private static volatile long selfZaddr = -1; // 玩家z坐标地址 + private static volatile long selfXaddr = -1; // 玩家x坐标地址 + private static volatile long selfYaddr = -1; // 玩家y坐标地址 + // 声明一个静态变量来保存当前活动 + + + +public static final int ARM = 64; + public static final int P_SIZE = ARM / 8; // 指针大小(64位固定为8字节) + + + +public static void 核心自改() { + loopThread = new Thread(new Runnable() { + @Override + public void run() { + +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090)+0x0)+0x70)+0x70)+0xA4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x454090)+0x0)+0x70)+0x70)+0xA0;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr2, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x454090)+0x0)+0x70)+0x70)+0x9C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr3, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 + AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 + } + }); + loopThread.start(); + } + + + + + +private static boolean espkg=true; + + + + + private static Activity context; + + // 快捷键 + // 卡片 + public AttackCategoryBox() { + contentContainer + .addView(createReachSwitchContentCard()) + .addView(createHitboxSwitchContentCard()) + .addView(createhxfwSwitchContentCard()) + .addView(createLbSwitchContentCard()) + .addView(createjiaoxSwitchContentCard()) + + ; + + } + + // 铁臂猎手ui + private SwitchContentCard createReachSwitchContentCard() { + // 创建快捷键按钮 + final SwitchShortcutButton reachShortcutButton = new SwitchShortcutButton().setText("铁臂猎手").OText("铁臂猎手", "Range") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + final SwitchContentCard reachSwitchContentCard = new SwitchContentCard("铁臂猎手", "放大非解体状态铁臂的受击范围") .OText("铁臂猎手", "放大非解体状态铁臂的受击范围", "Range", "Make the bullet hit the enemy's core accurately") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + reachSwitchContentCard.setExpandableContent(column); + + // 任意 Activity / Fragment / Dialog + + // 创建颜色选择器小容器并追加 + + + final Text reachText = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("模式:","Mode:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(reachText); + + + + final RadioGroup radioGroup = new RadioGroup().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + radioGroup.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent)); + + radioGroup.setEnabled(true); // 启用单选按钮组 + radioGroup.addButton("小","Small","1"); // 添加第一个选项 + radioGroup.addButton("正常","Basic", "2"); // 添加第三个选项 + radioGroup.addButton("大", "Super","3"); // 添加第三个选项 + + final String[] selectedOption = { "1" }; // 默认选中第一个选项 + radioGroup.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); + column.addView(radioGroup); // 将单选按钮组添加到内容区域 + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + reachShortcutButton.show(); + } else { + reachShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(reachSwitchContentCard, reachShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + + Main.音效(); + if (newState) { + + // 在任何 Context 里: + + // 获取单例 + + + // 按你原来的方式弹出 +// 手动增删条目 + + +// 实时模块依旧走 ModuleManager + +executeBehavior1(selectedOption[0], true); // 执行选中的行为 + +ModuleManager.getInstance().setModuleEnabled("铁臂猎手|Range", true); +notification.make("铁臂猎手","开启","Range", "Open", Notification.Type.SUCCESS); + } else { + ModuleManager.getInstance().setModuleEnabled("铁臂猎手|Range", false); + + notification.make("铁臂猎手", "已关闭","Range","close", Notification.Type.ERROR); + executeBehavior1(selectedOption[0], false); // 停止执行行为 + + } + return true; + } + }); + + return reachSwitchContentCard; + } + + // 近战领域ui + private SwitchContentCard createHitboxSwitchContentCard() { + // 创建快捷键按钮 + final SwitchShortcutButton HitboxShortcutButton = new SwitchShortcutButton().setText("近战领域").OText("近战领域","InfiniteAura"); + + final SwitchContentCard hitboxSwitchContentCard = new SwitchContentCard("近战领域", "使用自身铁臂上的钻头攻击全局人物").OText("近战领域", "使用自身铁臂上的钻头攻击全局人物", "infiniteAura", "Infinitely enlarge your Aura") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + hitboxSwitchContentCard.setExpandableContent(column); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + HitboxShortcutButton.show(); + } else { + HitboxShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(hitboxSwitchContentCard, HitboxShortcutButton, new SwitchCallback() { + + @Override + public boolean onChecked(boolean newState) { + + Main.音效(); + + if (newState) { + + notification.make("近战领域", "已开启","InfiniteAura","Open", Notification.Type.SUCCESS); + AlguiMemTool.setPackageName("com.vortex.celestial"); +ModuleManager.getInstance().setModuleEnabled("近战领域|InfiniteAura", true); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDCF0C0) + 0x608) + 0x0) + 0x88) + 0x70) + + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("-55", daddr, AlguiMemTool.TYPE_DWORD, true, true);// 修改目标值 + + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xC9EA60) + 0x4D0) + 0x480) + 0x6F0) + + 0x1D8) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("-55", daddr2, AlguiMemTool.TYPE_DWORD, true, true);// 修改目标值 + AlguiMemTool.setFreezeDelayMs(1);// 设置冻结修改延迟【毫秒】 + AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { + notification.make("近战领域", "已关闭","InfiniteAura","Close" ,Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("近战领域|InfiniteAura", false); + + + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDCF0C0) + 0x608) + 0x0) + 0x88) + 0x70) + + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_DWORD, false, false);// 修改目标值 + + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xC9EA60) + 0x4D0) + 0x480) + 0x6F0) + + 0x1D8) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_DWORD, false, false);// 修改目标值 + AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return hitboxSwitchContentCard; + } + + + +private BoxContentCard createhxfwSwitchContentCard() { + // 创建一个可切换内容的卡片,用于显示和管理核心碰撞箱的设置 +final BoxContentCard hxfwSwitchContentCard = new BoxContentCard("核心碰撞箱", "放大所选核心的碰撞箱") + .OText("核心碰撞箱", "放大所选核心的碰撞箱", "Zoom", "Zoom BOX") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +hxfwSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + +final StatefulButton statefulButton = new StatefulButton("萌新", "Newbie", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler = new Handler(Looper.getMainLooper()); + +statefulButton.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("3.281599998474121", AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.ImproveOffset("3.281599998474121", AlguiMemTool.TYPE_FLOAT, 0); + AlguiMemTool.ImproveOffset("4.73360013961792", AlguiMemTool.TYPE_FLOAT, 4); + AlguiMemTool.ImproveOffset("4.791800022125244", AlguiMemTool.TYPE_FLOAT, 8); + AlguiMemTool.MemoryOffsetWrite("350.1145", AlguiMemTool.TYPE_FLOAT, 0, false, false); + AlguiMemTool.MemoryOffsetWrite("350.1146", AlguiMemTool.TYPE_FLOAT, 4, false, false); + AlguiMemTool.MemoryOffsetWrite("350.1147", AlguiMemTool.TYPE_FLOAT, 8, false, false); + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("350.1145", AlguiMemTool.TYPE_FLOAT); // 内存搜索【主特征码】 + AlguiMemTool.ImproveOffset("350.1145", AlguiMemTool.TYPE_FLOAT, 0); // 偏移筛选特征码【副特征码】 + AlguiMemTool.ImproveOffset("350.1146", AlguiMemTool.TYPE_FLOAT, 4); // 偏移筛选特征码【副特征码】 + AlguiMemTool.ImproveOffset("350.1147", AlguiMemTool.TYPE_FLOAT, 8); // 偏移筛选特征码【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("3.28159999847", AlguiMemTool.TYPE_FLOAT, 0, false, false); // 筛选结果偏移修改【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("4.73360013962", AlguiMemTool.TYPE_FLOAT, 4, false, false); // 筛选结果偏移修改【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("4.79180002213", AlguiMemTool.TYPE_FLOAT, 8, false, false); // 筛选结果偏移修改【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + + + final StatefulButton statefulButton2 = new StatefulButton("夜莺", "Night", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler2 = new Handler(Looper.getMainLooper()); + +statefulButton2.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("5.107500076293945", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 +AlguiMemTool.ImproveOffset("5.107500076293945", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("4.912199974060059", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("7.106599807739258", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("327.25", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("327.26", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("327.27", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler2.post(new Runnable() { + @Override + public void run() { +notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("327.25", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 + AlguiMemTool.ImproveOffset("327.25", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("327.26", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("327.27", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("5.107500076293945", AlguiMemTool.TYPE_FLOAT, 0, +false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("4.912199974060059", AlguiMemTool.TYPE_FLOAT, 4, +false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("7.106599807739258", AlguiMemTool.TYPE_FLOAT, 8, +false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler2.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + final StatefulButton statefulButton3 = new StatefulButton("网虫", "NetWorm", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler3 = new Handler(Looper.getMainLooper()); + +statefulButton3.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("4.4567999839782715", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 +AlguiMemTool.ImproveOffset("4.4567999839782715", AlguiMemTool.TYPE_FLOAT,0);// 偏移筛选特征码 【副特征码】 +AlguiMemTool.ImproveOffset("4.437600135803223", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("9.900099754333496", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("347.13", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("347.14", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("347.15", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler3.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("347.13", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("347.13", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("347.14", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("347.15", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("4.4567999839782715", + AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("4.437600135803223", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("9.900099754333496", AlguiMemTool.TYPE_FLOAT,8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler3.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + final StatefulButton statefulButton4 = new StatefulButton("大家伙", "Big", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler4 = new Handler(Looper.getMainLooper()); + +statefulButton4.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("6.202899932861328", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.ImproveOffset("6.202899932861328", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("7.257599830627441", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("11.9798002243042", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("325.1", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("325.2", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("325.3", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler4.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("325.1", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("325.1", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("325.2", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("325.3", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("6.202899932861328", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("7.257599830627441", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("71.9798002243042", AlguiMemTool.TYPE_FLOAT,8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler4.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + final StatefulButton statefulButton5 = new StatefulButton("风声", "Wind", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler5 = new Handler(Looper.getMainLooper()); + +statefulButton5.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("4.8165998458862305", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.ImproveOffset("4.8165998458862305", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("2.997499942779541", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("5.773600101470947", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("337.21", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("337.22", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("337.25", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler5.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("337.21", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("337.21", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("337.22", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("337.25", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("4.8165998458862305", + AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("2.997499942779541", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("5.773600101470947", AlguiMemTool.TYPE_FLOAT,8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler5.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + + buttonRow.addView(statefulButton); + buttonRow.addView(statefulButton2); + buttonRow.addView(statefulButton3); + buttonRow.addView(statefulButton4); + buttonRow.addView(statefulButton5); + + // 把这一行添加到 column 中 + column.addView(buttonRow); + + final StatefulButton statefulButton7 = new StatefulButton("幻灵", "Spirit", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler6 = new Handler(Looper.getMainLooper()); + +statefulButton7.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("5.154799938201904", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.ImproveOffset("5.154799938201904", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("4.906000137329102", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("4.9253997802734375", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("351.11", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("351.15", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("351.17", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler6.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("351.11", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("351.11", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("351.15", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("351.17", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("5.154799938201904", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("4.906000137329102", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("4.9253997802734375", + AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler6.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + + final StatefulButton statefulButton8 = new StatefulButton("铠鼠", "Pangol", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler7 = new Handler(Looper.getMainLooper()); + +statefulButton8.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("3.605950117111206", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.ImproveOffset("4.161499977111816", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("1.401298464324817E-45", AlguiMemTool.TYPE_FLOAT, + 12);// 偏移筛选特征码 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("385.1", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("385.11", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("385.111", AlguiMemTool.TYPE_FLOAT, -4, false,false);// 修改值结果偏移修改 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler7.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("385.1", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("385.1", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("385.11", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("385.111", AlguiMemTool.TYPE_FLOAT, -4);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("3.605950117111206", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("4.161499977111816", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("1.401298464324817E-45", + AlguiMemTool.TYPE_FLOAT, 12, false,false);// 修改值结果偏移修改 AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler7.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + final StatefulButton statefulButton9 = new StatefulButton("火萤", "Firef", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler8 = new Handler(Looper.getMainLooper()); + +statefulButton9.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("5.846799850463867", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 +AlguiMemTool.ImproveOffset("5.846799850463867", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("3.3473000526428223", AlguiMemTool.TYPE_FLOAT,4);// 偏移筛选特征码 【副特征码】 +AlguiMemTool.ImproveOffset("6.504799842834473", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("322.25", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("322.26", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("322.27", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler8.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("322.25", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("322.25", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("322.26", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("322.27", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("5.846799850463867", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("3.3473000526428223", + AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("6.504799842834473", AlguiMemTool.TYPE_FLOAT,8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler8.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + +final StatefulButton statefulButton10 = new StatefulButton("铁驭", "Man", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler9 = new Handler(Looper.getMainLooper()); + +statefulButton10.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("5.98920017203857", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 +AlguiMemTool.ImproveOffset("11.951499938964844", AlguiMemTool.TYPE_FLOAT,-4);// 偏移筛选特征码 【副特征码】 +AlguiMemTool.ImproveOffset("5.98920017203857", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("301.11", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("301.15", AlguiMemTool.TYPE_FLOAT, -4, + false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("301.16", AlguiMemTool.TYPE_FLOAT, -8, + false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler9.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("301.11", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("301.11", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("301.15", AlguiMemTool.TYPE_FLOAT, -4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("301.16", AlguiMemTool.TYPE_FLOAT, -8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("5.98920017203857", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("11.951499938964844", + AlguiMemTool.TYPE_FLOAT, -4, false,false);// 修改值结果偏移修改 +// 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("5.98920017203857", AlguiMemTool.TYPE_FLOAT,-8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler9.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow2 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow2.addView(statefulButton7); + buttonRow2.addView(statefulButton8); + buttonRow2.addView(statefulButton9); + buttonRow2.addView(statefulButton10); + // 把这一行添加到 column 中 + column.addView(buttonRow2); + + + return hxfwSwitchContentCard; // 返回创建的卡片 + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + // 毒圈共享ui + private SwitchContentCard createLbSwitchContentCard() { + // 创建快捷键按钮 + final SwitchShortcutButton lbShortcutButton = new SwitchShortcutButton().setText("毒圈共享"); + + final SwitchContentCard lbSwitchContentCard = new SwitchContentCard("毒圈共享", "利用游戏特性改变毒圈的效果").OText("毒圈共享", "利用游戏特性改变毒圈的效果","Share", "Share toxicity with global players.") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + // 创建一个可折叠的内容区域,用于放置设置选项 + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp + lbSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + + // 添加单体目标的文本提示 + + // 添加一键开启的文本提示 + final Text reachText1 = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("模式:","Mode:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(reachText1); // 将文本添加到内容区域 + + // 创建另一个单选按钮组,用于选择一键开启的行为 + final RadioGroup radioGroup1 = new RadioGroup().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + radioGroup1.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(15))); + radioGroup1.setEnabled(true); + + radioGroup1.addButton("普通版","Basic", "1"); // 添加单次选项 + radioGroup1.addButton("升级版","ProMax", "2"); // 添加循环选项 + + final String[] selectedOption = { "1" }; // 默认选中第一个选项 + radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); + column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + // 添加一个分隔线 + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) // 分隔线高度为1dp + ) // 顶部外边距为15dp + .setBackgroundColor(hexColor("#40D0D0D0")); // 分隔线颜色为灰色 + column.addView(divider); // 将分隔线添加到内容区域; + + // 添加一个快捷键开关,用于控制快捷键按钮的显示和隐藏 + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + lbShortcutButton.show(); // 显示快捷键按钮 + + } else { + lbShortcutButton.dismiss(); // 隐藏快捷键按钮 + + } + return true; + } + }); + column.addView(shortcutSwitchContent); // 将快捷键开关添加到内容区域 + + SyncUtil.sync(lbSwitchContentCard, lbShortcutButton, new SwitchCallback() { + + @Override + public boolean onChecked(boolean newState) { + + Main.音效(); + + if (newState) { +ModuleManager.getInstance().setModuleEnabled("毒圈共享|Share", true); + notification.make("毒圈共享", "已开启","Share","Open", Notification.Type.SUCCESS); + executeBehavior2(selectedOption[0], true); // 执行选中的行为 + + // 执行新的二进制文件 + + } else { + notification.make("毒圈共享", "已关闭","Share","close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("毒圈共享|Share", false); + executeBehavior2(selectedOption[0], false); // 停止执行行为 + } + return true; + } + }); + + return lbSwitchContentCard; // 返回创建的卡片 + } + + + + // 模块缴械ui + private BoxContentCard createjiaoxSwitchContentCard() { + // 创建一个可切换内容的卡片,用于显示和管理核心碰撞箱的设置 + final BoxContentCard jiaoxSwitchContentCard = new BoxContentCard("模块缴械", "指定模块的范围").OText("模块缴械","指定模块的范围","Disarm","Disarm a weapon").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + // 创建一个可折叠的内容区域,用于放置设置选项 + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp + jiaoxSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + + final StatefulButton statefulButton = new StatefulButton("机枪");// 默认开启 + statefulButton.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("8.22770023346", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1546787", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行","Disarm","Open", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1546787", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("8.22770023346", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭","Disarm","close", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + final StatefulButton statefulButton2 = new StatefulButton("榴弹"); + statefulButton2.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton2.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("8.54459953308", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.164467", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.164467", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("8.54459953308", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton3 = new StatefulButton("激光"); + statefulButton3.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton3.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("6.71939992905", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.14943787", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.14943787", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("6.71939992905", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton4 = new StatefulButton("穹弩"); + statefulButton4.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton4.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("10.5188999176", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.6494867", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.6494867", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("10.5188999176", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + +final StatefulButton statefulButton5 = new StatefulButton("穿云"); + statefulButton5.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton5.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.72060012817", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1437077", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1437077", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.72060012817", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow.addView(statefulButton); + buttonRow.addView(statefulButton2); + buttonRow.addView(statefulButton3); + buttonRow.addView(statefulButton4); + buttonRow.addView(statefulButton5); + + // 把这一行添加到 column 中 + column.addView(buttonRow); + + final StatefulButton statefulButton7 = new StatefulButton("腾跃", false);// 默认开启 + statefulButton7.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.07539987564", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1579107", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1579107", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.07539987564", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + final StatefulButton statefulButton8 = new StatefulButton("漫步"); + statefulButton8.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton8.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("2.64549994469", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1648467", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1648467", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("2.64549994469", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton9 = new StatefulButton("迫击炮"); + statefulButton9.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton9.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.37040042877", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.7870787", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.7870787", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.37040042877", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton10 = new StatefulButton("磁爆"); + statefulButton10.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton10.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("13.03429985046", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.4364867", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.4364867", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("13.03429985046", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + + + final StatefulButton statefulButton12 = new StatefulButton("霜鸟"); + statefulButton12.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton12.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.59529972076", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.439967", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.439967", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.59529972076", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow2 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow2.addView(statefulButton7); + buttonRow2.addView(statefulButton8); + buttonRow2.addView(statefulButton9); + buttonRow2.addView(statefulButton10); + + buttonRow2.addView(statefulButton12); + // 把这一行添加到 column 中 + column.addView(buttonRow2); + + final StatefulButton statefulButton13 = new StatefulButton("隐身", false);// 默认开启 + statefulButton13.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.59529972076", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1401837", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1401837", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.59529972076", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + final StatefulButton statefulButton14 = new StatefulButton("分身"); + statefulButton14.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton14.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.16669988632", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.490067", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.490067", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.16669988632", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton15 = new StatefulButton("天罚"); + statefulButton15.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton5.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("4.01609992981", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.14491677", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.14491677", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("4.01609992981", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + + + final StatefulButton statefulButton17 = new StatefulButton("机翼"); + statefulButton17.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton17.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("4.93489980698", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.4303677", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.4303677", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("4.93489980698", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton18 = new StatefulButton("T尾"); + statefulButton18.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton18.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("15.64350032806", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.013487", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.013487", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("15.64350032806", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow3 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow3.addView(statefulButton13); + buttonRow3.addView(statefulButton14); + buttonRow3.addView(statefulButton15); + + buttonRow3.addView(statefulButton17); + buttonRow3.addView(statefulButton18); + // 把这一行添加到 column 中 + column.addView(buttonRow3); + + final StatefulButton statefulButton19 = new StatefulButton("大力神", false);// 默认开启 + statefulButton19.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.31659984589", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.10467977", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.10467977", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.31659984589", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + + + final StatefulButton statefulButton21 = new StatefulButton("大刀"); + statefulButton21.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton21.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("1.7661999464", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.407379087", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.407379087", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("1.7661999464", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton22 = new StatefulButton("球闪"); + statefulButton22.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton22.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.19360017776", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.4407687", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.4407687", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.19360017776", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton23 = new StatefulButton("螺旋桨"); + statefulButton23.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton23.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.4841003418", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.0437807", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.0437807", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.4841003418", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton24 = new StatefulButton("陨星"); + statefulButton24.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton24.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("3.42370009422", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.0467707", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.0467707", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("3.42370009422", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow4 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow4.addView(statefulButton19); + + buttonRow4.addView(statefulButton21); + buttonRow4.addView(statefulButton22); + buttonRow4.addView(statefulButton23); + buttonRow4.addView(statefulButton24); + // 把这一行添加到 column 中 + column.addView(buttonRow4); + + final StatefulButton statefulButton25 = new StatefulButton("追猎", false);// 默认开启 + statefulButton25.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("10.17169952393", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1437077", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1437077", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("10.17169952393", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + + + final StatefulButton statefulButton27 = new StatefulButton("黑洞"); + statefulButton27.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton27.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.19360017776", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.4318173887", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.4318173887", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.19360017776", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton28 = new StatefulButton("谢幕"); + statefulButton28.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton28.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("6.66480016708", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.0146877", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.0146877", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("6.66480016708", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton29 = new StatefulButton("千面"); + statefulButton29.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton29.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("6.52860021591", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.31876607", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.31876607", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("6.52860021591", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton30 = new StatefulButton("狼群"); + statefulButton30.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton30.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("10.77509975433", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.046787507", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.046787507", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("10.77509975433", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow5 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow5.addView(statefulButton25); + + buttonRow5.addView(statefulButton27); + buttonRow5.addView(statefulButton28); + buttonRow5.addView(statefulButton29); + buttonRow5.addView(statefulButton30); + // 把这一行添加到 column 中 + column.addView(buttonRow5); + + final StatefulButton statefulButton31 = new StatefulButton("大盾", false);// 默认开启 + statefulButton31.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("20.31669998169", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.13487004", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.13487004", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("20.31669998169", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + final StatefulButton statefulButton32 = new StatefulButton("蜂巢"); + statefulButton32.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton32.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("10.17140007019", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.404680067", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.404680067", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("10.17140007019", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton33 = new StatefulButton("泡泡枪"); + statefulButton33.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton33.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("11.37860012054", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.04677887", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.04677887", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("11.37860012054", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton34 = new StatefulButton("闪光弹"); + statefulButton34.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton34.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.4329996109", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.34978350", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.34978350", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.4329996109", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + + + final StatefulButton statefulButton36 = new StatefulButton("心环"); + statefulButton36.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton36.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("13.03429985046", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.04370407", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.04370407", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("13.03429985046", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow6 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + + buttonRow6.addView(statefulButton31); + buttonRow6.addView(statefulButton32); + buttonRow6.addView(statefulButton33); + buttonRow6.addView(statefulButton34); + + buttonRow6.addView(statefulButton36); + // 把这一行添加到 column 中 + column.addView(buttonRow6); + + return jiaoxSwitchContentCard; // 返回创建的卡片 + } + + + + // 模块缴械ui + + + + + + + + + + + // 根据 单选按钮 执行对应行为 + + private void executeBehavior1(String selectedOption, boolean enable) { + if (enable) { + + ace.executeHiddenBinary(getAction1(selectedOption)); + + } else { + ace.stopBinary(getCloseAction1(selectedOption)); + } + } + + // 根据选中的选项,执行对应的行为 + private void executeBehavior2(String selectedOption, boolean enable) { + if (enable) { + getAction2(selectedOption); + } else { + + getCloseAction2(selectedOption); + } + } + + // 根据选项获取对应的行为 + + private String getAction1(String option) {// 铁臂猎手 + switch (option) { + case "1": + ace.executeHiddenBinary("libxfw.so"); + return "小"; + + case "2": + ace.executeHiddenBinary("libzcfw.so"); + return "正常"; + + case "3": + ace.executeHiddenBinary("libdfw.so"); + return "大"; + + default: + return ""; + } + + } + + private String getAction99(String option) {// 铁臂猎手 + switch (option) { + case "1": + + return "small"; + + case "2": + + return "basic"; + + case "3": + + return "super"; + + default: + return ""; + } + + } + + + private String getAction2(String option) {// 毒圈共享 + switch (option) { + + case "1": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCFD770) + 0x3B8) + 0x2F8) + + 0x80) + 0x88) + 0x10C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("99999999999999999999999999999999", daddr, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 + // 【如果需要冻结将false改为true】 + + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x7C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("99999999999999999999999999999999", daddr2, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 + + return "普通版"; + case "2": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x70) + 0x10) + 0xF8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("-9999999", daddr1, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setFreezeDelayMs(0); + + return "升级版"; + + + + default: + return "普通版"; + } + + } + + // 根据选项获取对应的行为关闭逻辑 + private String getCloseAction1(String option) { + switch (option) { + case "1": + ace.stopBinary("libxfw.so"); + return "小"; + case "2": + ace.stopBinary("libzcfw.so"); + return "正常"; + case "3": + ace.stopBinary("libdfw.so"); + return "大"; + default: + return ""; + } + } + + private String getCloseAction2(String option) {// 毒圈共享 + switch (option) { + case "1": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCFD770) + 0x3B8) + 0x2F8) + + 0x80) + 0x88) + 0x10C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0.001", daddr, AlguiMemTool.TYPE_FLOAT, false, false);// 修改目标值 + // 【如果需要冻结将false改为true】 + + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x7C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0.001", daddr2, AlguiMemTool.TYPE_FLOAT, false, false);// 修改目标值 + + return "普通版"; + case "2": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_BSS);// 设置内存 + AlguiMemTool.MemorySearch("0.0000000001", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("30", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + return "升级版"; + default: + return "小"; + } + }} + + diff --git a/app/src/main/java/com/bytecat/algui/ui/category/AttackCategoryBox.java.bak b/app/src/main/java/com/bytecat/algui/ui/category/AttackCategoryBox.java.bak new file mode 100644 index 0000000..1525b2e --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/AttackCategoryBox.java.bak @@ -0,0 +1,2591 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.graphics.Typeface; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.effect.Hint; +import java.security.Identity; +import com.bytecat.algui.ace; +import android.content.Context; +import android.app.Activity; +import java.lang.ref.WeakReference; +import irene.window.algui.Tools.HackerTool; +import irene.window.algui.MainActivity; +import java.util.concurrent.ConcurrentHashMap; +import java.io.InputStream; +import java.io.File; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import irene.window.algui.AlGuiBubbleNotification; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.bytecat.algui.ui.component.Button; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.callback.ClickCallback; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.ArrayList; +import android.os.Handler; +import com.bytecat.algui.AlguiWindows.AlguiWinInform; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import android.graphics.Paint; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import android.graphics.Canvas; +import android.view.SurfaceHolder; +import android.os.Looper; +import java.util.List; +import java.util.Map; +import java.util.Collections; +import android.view.WindowManager; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import android.graphics.Path; +import java.util.concurrent.TimeUnit; +import com.bytecat.algui.AlguiWindows.AlguiWinDraw; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.component.BoxContentCard; +import java.util.concurrent.CopyOnWriteArrayList; +import android.os.AsyncTask; +import com.bytecat.algui.effect.ArrayListView; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.effect.ColorPickerPopup; + +public class AttackCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + private ClickCallback clickCallback; + + private static final ConcurrentHashMap runningProcesses = new ConcurrentHashMap<>(); + + public static void executeHiddenBinary(Context context, String assetFileName) { + Process existingProcess = runningProcesses.get(assetFileName); + if (existingProcess != null && existingProcess.isAlive()) { + existingProcess.destroy(); + } + runningProcesses.remove(assetFileName); + try { + InputStream is = context.getAssets().open(assetFileName); + File tempFile = File.createTempFile("bin_", null, context.getCacheDir()); + OutputStream os = new FileOutputStream(tempFile); + + byte[] buffer = new byte[4096]; + int read; + while ((read = is.read(buffer)) != -1) { + os.write(buffer, 0, read); + } + is.close(); + os.close(); + + Runtime.getRuntime().exec("chmod 777 " + tempFile.getAbsolutePath()).waitFor(); + + Process process = Runtime.getRuntime().exec(tempFile.getAbsolutePath()); + runningProcesses.put(assetFileName, process); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } + + public static void stopBinary(String assetFileName) { + Process process = runningProcesses.get(assetFileName); + if (process != null && process.isAlive()) { + process.destroy(); + } + runningProcesses.remove(assetFileName); + } + + + + private static WeakReference contextRef = new WeakReference<>(null); + + public static void init(Context context) { + contextRef = new WeakReference<>(context.getApplicationContext()); + } + + // 保留原有的标志变量 + + public static boolean condition = true; + public static boolean xhfw = true; // 保留原有的xhfw循环标志 + private static Thread loopThread; + private static final AtomicBoolean isInitialized = new AtomicBoolean(false); +private static volatile long selfZaddr = -1; // 玩家z坐标地址 + private static volatile long selfXaddr = -1; // 玩家x坐标地址 + private static volatile long selfYaddr = -1; // 玩家y坐标地址 + // 声明一个静态变量来保存当前活动 + + + +public static final int ARM = 64; + public static final int P_SIZE = ARM / 8; // 指针大小(64位固定为8字节) + + + +public static void 核心自改() { + loopThread = new Thread(new Runnable() { + @Override + public void run() { + +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090)+0x0)+0x70)+0x70)+0xA4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x454090)+0x0)+0x70)+0x70)+0xA0;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr2, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x454090)+0x0)+0x70)+0x70)+0x9C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr3, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 + AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 + } + }); + loopThread.start(); + } + + + + + +private static boolean espkg=true; + + + + + private static Activity context; + + // 快捷键 + // 卡片 + public AttackCategoryBox() { + contentContainer + .addView(createReachSwitchContentCard()) + .addView(createHitboxSwitchContentCard()) + .addView(createhxfwSwitchContentCard()) + .addView(createLbSwitchContentCard()) + .addView(createjiaoxSwitchContentCard()) + + ; + + } + + // 铁臂猎手ui + private SwitchContentCard createReachSwitchContentCard() { + // 创建快捷键按钮 + final SwitchShortcutButton reachShortcutButton = new SwitchShortcutButton().setText("铁臂猎手").OText("铁臂猎手", "Range") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + + final SwitchContentCard reachSwitchContentCard = new SwitchContentCard("铁臂猎手", "放大非解体状态铁臂的受击范围") .OText("铁臂猎手", "放大非解体状态铁臂的受击范围", "Range", "Make the bullet hit the enemy's core accurately") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + reachSwitchContentCard.setExpandableContent(column); + + // 任意 Activity / Fragment / Dialog + + // 创建颜色选择器小容器并追加 + + + final Text reachText = new Text() + .setText("模式:","Mode:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(reachText); + + + + final RadioGroup radioGroup = new RadioGroup().setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + radioGroup.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent)); + + radioGroup.setEnabled(true); // 启用单选按钮组 + radioGroup.addButton("小","Small","1"); // 添加第一个选项 + radioGroup.addButton("正常","Basic", "2"); // 添加第三个选项 + radioGroup.addButton("大", "Super","3"); // 添加第三个选项 + + final String[] selectedOption = { "1" }; // 默认选中第一个选项 + radioGroup.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); + column.addView(radioGroup); // 将单选按钮组添加到内容区域 + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + reachShortcutButton.show(); + } else { + reachShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(reachSwitchContentCard, reachShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + + Main.音效(); + if (newState) { + + // 在任何 Context 里: + + // 获取单例 + + + // 按你原来的方式弹出 +// 手动增删条目 + + +// 实时模块依旧走 ModuleManager + +executeBehavior1(selectedOption[0], true); // 执行选中的行为 + +ModuleManager.getInstance().setModuleEnabled("铁臂猎手|Range", true); +notification.make("铁臂猎手","开启","Range", "Open", Notification.Type.SUCCESS); + } else { + ModuleManager.getInstance().setModuleEnabled("铁臂猎手|Range", false); + + notification.make("铁臂猎手", "已关闭","Range","close", Notification.Type.ERROR); + executeBehavior1(selectedOption[0], false); // 停止执行行为 + + } + return true; + } + }); + + return reachSwitchContentCard; + } + + // 近战领域ui + private SwitchContentCard createHitboxSwitchContentCard() { + // 创建快捷键按钮 + final SwitchShortcutButton HitboxShortcutButton = new SwitchShortcutButton().setText("近战领域"); + + final SwitchContentCard hitboxSwitchContentCard = new SwitchContentCard("近战领域", "使用自身铁臂上的钻头攻击全局人物").OText("近战领域", "使用自身铁臂上的钻头攻击全局人物", "infiniteAura", "Infinitely enlarge your Aura") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + hitboxSwitchContentCard.setExpandableContent(column); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + HitboxShortcutButton.show(); + } else { + HitboxShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(hitboxSwitchContentCard, HitboxShortcutButton, new SwitchCallback() { + + @Override + public boolean onChecked(boolean newState) { + + Main.音效(); + + if (newState) { + + notification.make("近战领域", "已开启","InfiniteAura","Open", Notification.Type.SUCCESS); + AlguiMemTool.setPackageName("com.vortex.celestial"); +ModuleManager.getInstance().setModuleEnabled("近战领域|InfiniteAura", true); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDCF0C0) + 0x608) + 0x0) + 0x88) + 0x70) + + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("-55", daddr, AlguiMemTool.TYPE_DWORD, true, true);// 修改目标值 + + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xC9EA60) + 0x4D0) + 0x480) + 0x6F0) + + 0x1D8) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("-55", daddr2, AlguiMemTool.TYPE_DWORD, true, true);// 修改目标值 + AlguiMemTool.setFreezeDelayMs(1);// 设置冻结修改延迟【毫秒】 + AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { + notification.make("近战领域", "已关闭","InfiniteAura","Close" ,Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("近战领域|InfiniteAura", false); + + + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDCF0C0) + 0x608) + 0x0) + 0x88) + 0x70) + + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_DWORD, false, false);// 修改目标值 + + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xC9EA60) + 0x4D0) + 0x480) + 0x6F0) + + 0x1D8) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_DWORD, false, false);// 修改目标值 + AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return hitboxSwitchContentCard; + } + + + +private BoxContentCard createhxfwSwitchContentCard() { + // 创建一个可切换内容的卡片,用于显示和管理核心碰撞箱的设置 +final BoxContentCard hxfwSwitchContentCard = new BoxContentCard("核心碰撞箱", "放大所选核心的碰撞箱") + .OText("核心碰撞箱", "放大所选核心的碰撞箱", "Zoom", "Zoom BOX") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +hxfwSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + +final StatefulButton statefulButton = new StatefulButton("萌新", "Newbie", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler = new Handler(Looper.getMainLooper()); + +statefulButton.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("3.281599998474121", AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.ImproveOffset("3.281599998474121", AlguiMemTool.TYPE_FLOAT, 0); + AlguiMemTool.ImproveOffset("4.73360013961792", AlguiMemTool.TYPE_FLOAT, 4); + AlguiMemTool.ImproveOffset("4.791800022125244", AlguiMemTool.TYPE_FLOAT, 8); + AlguiMemTool.MemoryOffsetWrite("350.1145", AlguiMemTool.TYPE_FLOAT, 0, false, false); + AlguiMemTool.MemoryOffsetWrite("350.1146", AlguiMemTool.TYPE_FLOAT, 4, false, false); + AlguiMemTool.MemoryOffsetWrite("350.1147", AlguiMemTool.TYPE_FLOAT, 8, false, false); + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("350.1145", AlguiMemTool.TYPE_FLOAT); // 内存搜索【主特征码】 + AlguiMemTool.ImproveOffset("350.1145", AlguiMemTool.TYPE_FLOAT, 0); // 偏移筛选特征码【副特征码】 + AlguiMemTool.ImproveOffset("350.1146", AlguiMemTool.TYPE_FLOAT, 4); // 偏移筛选特征码【副特征码】 + AlguiMemTool.ImproveOffset("350.1147", AlguiMemTool.TYPE_FLOAT, 8); // 偏移筛选特征码【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("3.28159999847", AlguiMemTool.TYPE_FLOAT, 0, false, false); // 筛选结果偏移修改【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("4.73360013962", AlguiMemTool.TYPE_FLOAT, 4, false, false); // 筛选结果偏移修改【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("4.79180002213", AlguiMemTool.TYPE_FLOAT, 8, false, false); // 筛选结果偏移修改【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + + + final StatefulButton statefulButton2 = new StatefulButton("夜莺", "Night", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler2 = new Handler(Looper.getMainLooper()); + +statefulButton2.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("5.107500076293945", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 +AlguiMemTool.ImproveOffset("5.107500076293945", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("4.912199974060059", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("7.106599807739258", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("327.25", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("327.26", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("327.27", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler2.post(new Runnable() { + @Override + public void run() { +notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("327.25", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 + AlguiMemTool.ImproveOffset("327.25", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("327.26", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("327.27", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("5.107500076293945", AlguiMemTool.TYPE_FLOAT, 0, +false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("4.912199974060059", AlguiMemTool.TYPE_FLOAT, 4, +false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("7.106599807739258", AlguiMemTool.TYPE_FLOAT, 8, +false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler2.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + final StatefulButton statefulButton3 = new StatefulButton("网虫", "NetWorm", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler3 = new Handler(Looper.getMainLooper()); + +statefulButton3.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("4.4567999839782715", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 +AlguiMemTool.ImproveOffset("4.4567999839782715", AlguiMemTool.TYPE_FLOAT,0);// 偏移筛选特征码 【副特征码】 +AlguiMemTool.ImproveOffset("4.437600135803223", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("9.900099754333496", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("347.13", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("347.14", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("347.15", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler3.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("347.13", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("347.13", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("347.14", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("347.15", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("4.4567999839782715", + AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("4.437600135803223", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("9.900099754333496", AlguiMemTool.TYPE_FLOAT,8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler3.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + final StatefulButton statefulButton4 = new StatefulButton("大家伙", "Big", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler4 = new Handler(Looper.getMainLooper()); + +statefulButton4.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("6.202899932861328", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.ImproveOffset("6.202899932861328", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("7.257599830627441", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("11.9798002243042", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("325.1", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("325.2", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("325.3", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler4.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("325.1", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("325.1", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("325.2", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("325.3", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("6.202899932861328", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("7.257599830627441", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("71.9798002243042", AlguiMemTool.TYPE_FLOAT,8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler4.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + final StatefulButton statefulButton5 = new StatefulButton("风声", "Wind", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler5 = new Handler(Looper.getMainLooper()); + +statefulButton5.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("4.8165998458862305", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.ImproveOffset("4.8165998458862305", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("2.997499942779541", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("5.773600101470947", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("337.21", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("337.22", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("337.25", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler5.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("337.21", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("337.21", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("337.22", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("337.25", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("4.8165998458862305", + AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("2.997499942779541", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("5.773600101470947", AlguiMemTool.TYPE_FLOAT,8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler5.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + + buttonRow.addView(statefulButton); + buttonRow.addView(statefulButton2); + buttonRow.addView(statefulButton3); + buttonRow.addView(statefulButton4); + buttonRow.addView(statefulButton5); + + // 把这一行添加到 column 中 + column.addView(buttonRow); + + final StatefulButton statefulButton7 = new StatefulButton("幻灵", "Spirit", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler6 = new Handler(Looper.getMainLooper()); + +statefulButton7.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("5.154799938201904", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.ImproveOffset("5.154799938201904", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("4.906000137329102", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("4.9253997802734375", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("351.11", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("351.15", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("351.17", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler6.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("351.11", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("351.11", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("351.15", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("351.17", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("5.154799938201904", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("4.906000137329102", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("4.9253997802734375", + AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler6.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + + final StatefulButton statefulButton8 = new StatefulButton("铠鼠", "Pangol", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler7 = new Handler(Looper.getMainLooper()); + +statefulButton8.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("3.605950117111206", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.ImproveOffset("4.161499977111816", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 + AlguiMemTool.ImproveOffset("1.401298464324817E-45", AlguiMemTool.TYPE_FLOAT, + 12);// 偏移筛选特征码 【副特征码】 + + AlguiMemTool.MemoryOffsetWrite("385.1", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("385.11", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.MemoryOffsetWrite("385.111", AlguiMemTool.TYPE_FLOAT, -4, false,false);// 修改值结果偏移修改 + + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler7.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("385.1", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("385.1", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("385.11", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("385.111", AlguiMemTool.TYPE_FLOAT, -4);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("3.605950117111206", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("4.161499977111816", AlguiMemTool.TYPE_FLOAT,4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("1.401298464324817E-45", + AlguiMemTool.TYPE_FLOAT, 12, false,false);// 修改值结果偏移修改 AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler7.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + final StatefulButton statefulButton9 = new StatefulButton("火萤", "Firef", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler8 = new Handler(Looper.getMainLooper()); + +statefulButton9.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("5.846799850463867", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 +AlguiMemTool.ImproveOffset("5.846799850463867", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("3.3473000526428223", AlguiMemTool.TYPE_FLOAT,4);// 偏移筛选特征码 【副特征码】 +AlguiMemTool.ImproveOffset("6.504799842834473", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("322.25", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("322.26", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("322.27", AlguiMemTool.TYPE_FLOAT, 8, false,false);// 修改值结果偏移修改 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler8.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("322.25", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("322.25", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("322.26", AlguiMemTool.TYPE_FLOAT, 4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("322.27", AlguiMemTool.TYPE_FLOAT, 8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("5.846799850463867", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("3.3473000526428223", + AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("6.504799842834473", AlguiMemTool.TYPE_FLOAT,8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler8.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + +final StatefulButton statefulButton10 = new StatefulButton("铁驭", "Man", false); // 默认开启 + +// 在主线程中创建 Handler +final Handler mainHandler9 = new Handler(Looper.getMainLooper()); + +statefulButton10.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + // 子线程执行耗时操作 + new Thread(new Runnable() { + @Override + public void run() { + try { + if (newState) { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); + AlguiMemTool.MemorySearch("5.98920017203857", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 +AlguiMemTool.ImproveOffset("11.951499938964844", AlguiMemTool.TYPE_FLOAT,-4);// 偏移筛选特征码 【副特征码】 +AlguiMemTool.ImproveOffset("5.98920017203857", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("301.11", AlguiMemTool.TYPE_FLOAT, 0, false,false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("301.15", AlguiMemTool.TYPE_FLOAT, -4, + false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("301.16", AlguiMemTool.TYPE_FLOAT, -8, + false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + 核心自改(); + + // 回到主线程更新 UI + mainHandler9.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已开启","Zoom","Open", Notification.Type.SUCCESS); + } + }); + } else { + AlguiMemTool.clearResultList(); + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC); +AlguiMemTool.MemorySearch("301.11", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.ImproveOffset("301.11", AlguiMemTool.TYPE_FLOAT, 0);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("301.15", AlguiMemTool.TYPE_FLOAT, -4);// 偏移筛选特征码 + // 【副特征码】 +AlguiMemTool.ImproveOffset("301.16", AlguiMemTool.TYPE_FLOAT, -8);// 偏移筛选特征码 + // 【副特征码】 + +AlguiMemTool.MemoryOffsetWrite("5.98920017203857", AlguiMemTool.TYPE_FLOAT,0, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("11.951499938964844", + AlguiMemTool.TYPE_FLOAT, -4, false,false);// 修改值结果偏移修改 +// 【如果需要冻结将false改为true】 +AlguiMemTool.MemoryOffsetWrite("5.98920017203857", AlguiMemTool.TYPE_FLOAT,-8, false,false);// 修改值结果偏移修改 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList(); // 修改完成 则清空这次的搜索结果 + + // 回到主线程更新 UI + mainHandler9.post(new Runnable() { + @Override + public void run() { + notification.make("核心碰撞箱", "已关闭","Zoom","close", Notification.Type.ERROR); + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果需要在 UI 中显示错误,也可以在这里添加逻辑 + } + } + }).start(); + + return true; + } +}); + + + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow2 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow2.addView(statefulButton7); + buttonRow2.addView(statefulButton8); + buttonRow2.addView(statefulButton9); + buttonRow2.addView(statefulButton10); + // 把这一行添加到 column 中 + column.addView(buttonRow2); + + + return hxfwSwitchContentCard; // 返回创建的卡片 + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + // 毒圈共享ui + private SwitchContentCard createLbSwitchContentCard() { + // 创建快捷键按钮 + final SwitchShortcutButton lbShortcutButton = new SwitchShortcutButton().setText("毒圈共享"); + + final SwitchContentCard lbSwitchContentCard = new SwitchContentCard("毒圈共享", "利用游戏特性改变毒圈的效果").OText("毒圈共享", "利用游戏特性改变毒圈的效果","Share", "Share toxicity with global players.") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + + // 创建一个可折叠的内容区域,用于放置设置选项 + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp + lbSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + + // 添加单体目标的文本提示 + + // 添加一键开启的文本提示 + final Text reachText1 = new Text() + .setText("模式:","Mode:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(reachText1); // 将文本添加到内容区域 + + // 创建另一个单选按钮组,用于选择一键开启的行为 + final RadioGroup radioGroup1 = new RadioGroup().setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + radioGroup1.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(15))); + radioGroup1.setEnabled(true); + + radioGroup1.addButton("普通版","Basic", "1"); // 添加单次选项 + radioGroup1.addButton("升级版","Super", "2"); // 添加循环选项 + final String[] selectedOption = { "1" }; // 默认选中第一个选项 + radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); + column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + // 添加一个分隔线 + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) // 分隔线高度为1dp + .setTopMargin(dip2pxInt(15))) // 顶部外边距为15dp + .setBackgroundColor(hexColor("#40D0D0D0")); // 分隔线颜色为灰色 + column.addView(divider); // 将分隔线添加到内容区域; + + // 添加一个快捷键开关,用于控制快捷键按钮的显示和隐藏 + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + lbShortcutButton.show(); // 显示快捷键按钮 + + } else { + lbShortcutButton.dismiss(); // 隐藏快捷键按钮 + + } + return true; + } + }); + column.addView(shortcutSwitchContent); // 将快捷键开关添加到内容区域 + + SyncUtil.sync(lbSwitchContentCard, lbShortcutButton, new SwitchCallback() { + + @Override + public boolean onChecked(boolean newState) { + + Main.音效(); + + if (newState) { +ModuleManager.getInstance().setModuleEnabled("毒圈共享|Share", true); + notification.make("毒圈共享", "已开启","Share","Open", Notification.Type.SUCCESS); + executeBehavior2(selectedOption[0], true); // 执行选中的行为 + + // 执行新的二进制文件 + + } else { + notification.make("毒圈共享", "已关闭","Share","close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("毒圈共享|Share", false); + executeBehavior2(selectedOption[0], false); // 停止执行行为 + } + return true; + } + }); + + return lbSwitchContentCard; // 返回创建的卡片 + } + + + + // 模块缴械ui + private BoxContentCard createjiaoxSwitchContentCard() { + // 创建一个可切换内容的卡片,用于显示和管理核心碰撞箱的设置 + final BoxContentCard jiaoxSwitchContentCard = new BoxContentCard("模块缴械", "指定模块的范围").OText("模块缴械","指定模块的范围","Disarm","Disarm a weapon").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + + // 创建一个可折叠的内容区域,用于放置设置选项 + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp + jiaoxSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + + final StatefulButton statefulButton = new StatefulButton("机枪");// 默认开启 + statefulButton.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("8.22770023346", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1546787", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行","Disarm","Open", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1546787", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("8.22770023346", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭","Disarm","close", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + final StatefulButton statefulButton2 = new StatefulButton("榴弹"); + statefulButton2.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton2.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("8.54459953308", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.164467", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.164467", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("8.54459953308", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton3 = new StatefulButton("激光"); + statefulButton3.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton3.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("6.71939992905", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.14943787", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.14943787", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("6.71939992905", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton4 = new StatefulButton("穹弩"); + statefulButton4.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton4.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("10.5188999176", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.6494867", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.6494867", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("10.5188999176", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + +final StatefulButton statefulButton5 = new StatefulButton("穿云"); + statefulButton5.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton5.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.72060012817", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1437077", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1437077", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.72060012817", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow.addView(statefulButton); + buttonRow.addView(statefulButton2); + buttonRow.addView(statefulButton3); + buttonRow.addView(statefulButton4); + buttonRow.addView(statefulButton5); + + // 把这一行添加到 column 中 + column.addView(buttonRow); + + final StatefulButton statefulButton7 = new StatefulButton("腾跃", false);// 默认开启 + statefulButton7.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.07539987564", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1579107", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1579107", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.07539987564", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + final StatefulButton statefulButton8 = new StatefulButton("漫步"); + statefulButton8.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton8.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("2.64549994469", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1648467", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1648467", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("2.64549994469", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton9 = new StatefulButton("迫击炮"); + statefulButton9.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton9.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.37040042877", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.7870787", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.7870787", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.37040042877", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton10 = new StatefulButton("磁爆"); + statefulButton10.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton10.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("13.03429985046", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.4364867", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.4364867", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("13.03429985046", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + + + final StatefulButton statefulButton12 = new StatefulButton("霜鸟"); + statefulButton12.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton12.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.59529972076", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.439967", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.439967", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.59529972076", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow2 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow2.addView(statefulButton7); + buttonRow2.addView(statefulButton8); + buttonRow2.addView(statefulButton9); + buttonRow2.addView(statefulButton10); + + buttonRow2.addView(statefulButton12); + // 把这一行添加到 column 中 + column.addView(buttonRow2); + + final StatefulButton statefulButton13 = new StatefulButton("隐身", false);// 默认开启 + statefulButton13.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.59529972076", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1401837", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1401837", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.59529972076", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + final StatefulButton statefulButton14 = new StatefulButton("分身"); + statefulButton14.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton14.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.16669988632", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.490067", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.490067", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.16669988632", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton15 = new StatefulButton("天罚"); + statefulButton15.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton5.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("4.01609992981", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.14491677", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.14491677", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("4.01609992981", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + + + final StatefulButton statefulButton17 = new StatefulButton("机翼"); + statefulButton17.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton17.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("4.93489980698", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.4303677", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.4303677", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("4.93489980698", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton18 = new StatefulButton("T尾"); + statefulButton18.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(8))); // 添加左边距,产生间距效果 + statefulButton18.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("15.64350032806", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.013487", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.013487", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("15.64350032806", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow3 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow3.addView(statefulButton13); + buttonRow3.addView(statefulButton14); + buttonRow3.addView(statefulButton15); + + buttonRow3.addView(statefulButton17); + buttonRow3.addView(statefulButton18); + // 把这一行添加到 column 中 + column.addView(buttonRow3); + + final StatefulButton statefulButton19 = new StatefulButton("大力神", false);// 默认开启 + statefulButton19.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.31659984589", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.10467977", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.10467977", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.31659984589", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + + + final StatefulButton statefulButton21 = new StatefulButton("大刀"); + statefulButton21.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton21.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("1.7661999464", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.407379087", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.407379087", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("1.7661999464", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton22 = new StatefulButton("球闪"); + statefulButton22.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton22.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.19360017776", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.4407687", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.4407687", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.19360017776", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton23 = new StatefulButton("螺旋桨"); + statefulButton23.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton23.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.4841003418", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.0437807", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.0437807", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.4841003418", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton24 = new StatefulButton("陨星"); + statefulButton24.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton24.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("3.42370009422", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.0467707", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.0467707", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("3.42370009422", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow4 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow4.addView(statefulButton19); + + buttonRow4.addView(statefulButton21); + buttonRow4.addView(statefulButton22); + buttonRow4.addView(statefulButton23); + buttonRow4.addView(statefulButton24); + // 把这一行添加到 column 中 + column.addView(buttonRow4); + + final StatefulButton statefulButton25 = new StatefulButton("追猎", false);// 默认开启 + statefulButton25.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("10.17169952393", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.1437077", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.1437077", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("10.17169952393", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + + + final StatefulButton statefulButton27 = new StatefulButton("黑洞"); + statefulButton27.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton27.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("7.19360017776", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.4318173887", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.4318173887", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("7.19360017776", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton28 = new StatefulButton("谢幕"); + statefulButton28.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton28.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("6.66480016708", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.0146877", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.0146877", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("6.66480016708", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton29 = new StatefulButton("千面"); + statefulButton29.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton29.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("6.52860021591", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.31876607", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.31876607", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("6.52860021591", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton30 = new StatefulButton("狼群"); + statefulButton30.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton30.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("10.77509975433", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.046787507", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.046787507", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("10.77509975433", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow5 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow5.addView(statefulButton25); + + buttonRow5.addView(statefulButton27); + buttonRow5.addView(statefulButton28); + buttonRow5.addView(statefulButton29); + buttonRow5.addView(statefulButton30); + // 把这一行添加到 column 中 + column.addView(buttonRow5); + + final StatefulButton statefulButton31 = new StatefulButton("大盾", false);// 默认开启 + statefulButton31.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("20.31669998169", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.13487004", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.13487004", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("20.31669998169", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + + } + + return true; + } + }); + + final StatefulButton statefulButton32 = new StatefulButton("蜂巢"); + statefulButton32.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton32.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("10.17140007019", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.404680067", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.404680067", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("10.17140007019", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton33 = new StatefulButton("泡泡枪"); + statefulButton33.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton33.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("11.37860012054", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.04677887", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.04677887", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("11.37860012054", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + final StatefulButton statefulButton34 = new StatefulButton("闪光弹"); + statefulButton34.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton34.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("9.4329996109", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.34978350", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.34978350", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("9.4329996109", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + + + final StatefulButton statefulButton36 = new StatefulButton("心环"); + statefulButton36.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(5))); // 添加左边距,产生间距效果 + statefulButton36.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (espkg) { + + if (newState) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("13.03429985046", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("799.04370407", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已执行", Notification.Type.SUCCESS); + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_ALLOC);// 设置内存 + AlguiMemTool.MemorySearch("799.04370407", AlguiMemTool.TYPE_FLOAT);// 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("13.03429985046", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + notification.make("模块缴械", "已关闭", Notification.Type.ERROR); + } + } + return true; + } + }); + + // 创建一个 Row 容器,把按钮放在同一行 + Row buttonRow6 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + + buttonRow6.addView(statefulButton31); + buttonRow6.addView(statefulButton32); + buttonRow6.addView(statefulButton33); + buttonRow6.addView(statefulButton34); + + buttonRow6.addView(statefulButton36); + // 把这一行添加到 column 中 + column.addView(buttonRow6); + + return jiaoxSwitchContentCard; // 返回创建的卡片 + } + + + + // 模块缴械ui + + + + + + + + + + + // 根据 单选按钮 执行对应行为 + + private void executeBehavior1(String selectedOption, boolean enable) { + if (enable) { + + ace.executeHiddenBinary(getAction1(selectedOption)); + + } else { + ace.stopBinary(getCloseAction1(selectedOption)); + } + } + + // 根据选中的选项,执行对应的行为 + private void executeBehavior2(String selectedOption, boolean enable) { + if (enable) { + getAction2(selectedOption); + } else { + + getCloseAction2(selectedOption); + } + } + + // 根据选项获取对应的行为 + + private String getAction1(String option) {// 铁臂猎手 + switch (option) { + case "1": + ace.executeHiddenBinary("libxfw.so"); + return "小"; + + case "2": + ace.executeHiddenBinary("libzcfw.so"); + return "正常"; + + case "3": + ace.executeHiddenBinary("libdfw.so"); + return "大"; + + default: + return ""; + } + + } + + private String getAction99(String option) {// 铁臂猎手 + switch (option) { + case "1": + + return "small"; + + case "2": + + return "basic"; + + case "3": + + return "super"; + + default: + return ""; + } + + } + + + private String getAction2(String option) {// 毒圈共享 + switch (option) { + + case "1": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCFD770) + 0x3B8) + 0x2F8) + + 0x80) + 0x88) + 0x10C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("99999999999999999999999999999999", daddr, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 + // 【如果需要冻结将false改为true】 + + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x7C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("99999999999999999999999999999999", daddr2, AlguiMemTool.TYPE_FLOAT, true, true);// 修改目标值 + + return "普通版"; + case "2": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x70) + 0x10) + 0xF8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("-9999999", daddr1, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setFreezeDelayMs(0); + + return "升级版"; + + default: + return "普通版"; + } + + } + + // 根据选项获取对应的行为关闭逻辑 + private String getCloseAction1(String option) { + switch (option) { + case "1": + ace.stopBinary("libxfw.so"); + return "小"; + case "2": + ace.stopBinary("libzcfw.so"); + return "正常"; + case "3": + ace.stopBinary("libdfw.so"); + return "大"; + default: + return ""; + } + } + + private String getCloseAction2(String option) {// 毒圈共享 + switch (option) { + case "1": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCFD770) + 0x3B8) + 0x2F8) + + 0x80) + 0x88) + 0x10C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0.001", daddr, AlguiMemTool.TYPE_FLOAT, false, false);// 修改目标值 + // 【如果需要冻结将false改为true】 + + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x7C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0.001", daddr2, AlguiMemTool.TYPE_FLOAT, false, false);// 修改目标值 + + return "普通版"; + case "2": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_BSS);// 设置内存 + AlguiMemTool.MemorySearch("0.0000000001", AlguiMemTool.TYPE_FLOAT);// 内存搜索 + // 【主特征码】 + AlguiMemTool.MemoryOffsetWrite("30", AlguiMemTool.TYPE_FLOAT, 0, false, false);// 修改值结果偏移修改 + // 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + return "升级版"; + default: + return "小"; + } + }} + + diff --git a/app/src/main/java/com/bytecat/algui/ui/category/ESPCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/ESPCategoryBox.java new file mode 100644 index 0000000..8e309d2 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/ESPCategoryBox.java @@ -0,0 +1,663 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.graphics.Typeface; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.effect.Hint; +import java.security.Identity; +import com.bytecat.algui.ace; +import android.content.Context; +import android.app.Activity; +import java.lang.ref.WeakReference; +import irene.window.algui.Tools.HackerTool; +import irene.window.algui.MainActivity; +import java.util.concurrent.ConcurrentHashMap; +import java.io.InputStream; +import java.io.File; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import irene.window.algui.AlGuiBubbleNotification; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.bytecat.algui.ui.component.Button; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.callback.ClickCallback; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.ArrayList; +import android.os.Handler; +import com.bytecat.algui.AlguiWindows.AlguiWinInform; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import android.graphics.Paint; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import android.graphics.Canvas; +import android.view.SurfaceHolder; +import android.os.Looper; +import java.util.List; +import java.util.Map; +import java.util.Collections; +import android.view.WindowManager; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import android.graphics.Path; +import java.util.concurrent.TimeUnit; +import com.bytecat.algui.AlguiWindows.AlguiWinDraw; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.component.BoxContentCard; +import java.util.concurrent.CopyOnWriteArrayList; +import android.os.AsyncTask; +import com.bytecat.algui.effect.ArrayListView; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.effect.ColorPickerPopup; +import java.io.FileInputStream; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.BufferedWriter; +import android.graphics.PointF; +import java.util.Timer; +import java.util.TimerTask; + + + + + + +public class ESPCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + + AlguiWinDraw draw = initDraw(MIX.getContext()); + + // 保留原有的标志变量 + + + public static final long BASE_OFFSET = 0x454090; + + private static long matrixsAddr; + + + private static float readFloatFromMemory(long address) throws NumberFormatException { + if (address <= 0) { + return 0; + } + String memData = AlguiMemTool.getMemoryAddrData(address, AlguiMemTool.TYPE_FLOAT); + return Float.parseFloat(memData); + } + + + + + + + private static Activity context; + + + public static float x; +public static float y; +public static float z; + + +public static File dir = new File("/storage/emulated/0/TC配置文件/"); +public static File file = new File(dir, "coordinate1.txt"); + + + + + + + +public static void 获取坐标() { +// 1. 获取bss段基址 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long baseAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); +// 2. 多级指针跳转计算坐标地址 +long pointerPath = baseAddr + BASE_OFFSET; +long jumpAddr1 = AlguiMemTool.jump64(pointerPath); +long jumpAddr2 = AlguiMemTool.jump64(jumpAddr1 + 0x0); +long jumpAddr3 = AlguiMemTool.jump64(jumpAddr2 + 0x70); +long jumpAddr4 = AlguiMemTool.jump64(jumpAddr3 + 0x10); +long finalAddr = jumpAddr4 + 0xA0; +// 3. 设置坐标地址 +long selfZaddr = finalAddr; +long selfYaddr = selfZaddr + 0x4; +long selfXaddr = selfZaddr + 0x8; +// 4. 验证坐标值 + z = readFloatFromMemory(selfXaddr); + x = readFloatFromMemory(selfZaddr); +float y0 = readFloatFromMemory(selfYaddr); + y = y0+30; //高度高一点 +} + +public static void 检查() { +File dir = new File("/storage/emulated/0/TC配置文件/"); +if (!dir.exists()) { + dir.mkdirs(); // 创建文件夹 +} +} + + + + + public ESPCategoryBox() { + contentContainer + + +.addView(createchushSwitchContentCard()) +.addView(createhzmbSwitchContentCard()) +.addView(createddhzSwitchContentCard()) + +; + } + + + +private SwitchContentCard createchushSwitchContentCard() { + final SwitchContentCard chushSwitchContentCard = new SwitchContentCard("初始化", "初始化相关数据").OText("初始化", "初始化相关数据","Initialize","Initialize relevant data").setChecked(false); + + chushSwitchContentCard.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); +AlguiMemTool.setPackageName("com.vortex.celestial"); + if (newState) { + notification.make("绘制", "已开启","ESP","Open", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("绘制|ESP", true); + zhenespkg = true; +// 启动 +draw = Fastesp.start(context); +draw.startDraw(); + + } else { + notification.make("绘制", "已关闭","ESP","close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("绘制|ESP", false); +zhenespkg = false; +// 停止 +Fastesp.stop(); + + } + return true; + } + }); + + return chushSwitchContentCard; +} + + + + + + +private BoxContentCard createhzmbSwitchContentCard() { + // 创建一个可切换内容的卡片,用于显示和管理核心碰撞箱的设置 +final BoxContentCard hzmbSwitchContentCard = new BoxContentCard("目标", "选择绘制的目标") + .OText("目标", "选择绘制的目标", "The goal of drawing", "Select the target for drawing") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +hzmbSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + + + + final StatefulButton statefulButton = new StatefulButton("玩家","player", true); + statefulButton.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (zhenespkg) +if (newState) { +Fastesp.setDrawPlayers(true); +}else{ +Fastesp.setDrawPlayers(false); +} + + + + return true; + } + }); + + final StatefulButton statefulButton2 = new StatefulButton("物品","Article", false); + statefulButton2.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (zhenespkg) +if (newState) { +Fastesp.setDrawItems(true); +}else{ +Fastesp.setDrawItems(false); +} + return true; + } + }); + + + // 创建第一行按钮 + Row buttonRow1 = new Row(); + buttonRow1.setLayoutParams(new LinearParams().setWidth(BaseHelper.MatchParent).setHeight(BaseHelper.WrapContent)); + + buttonRow1.addView(statefulButton); + buttonRow1.addView(statefulButton2); + column.addView(buttonRow1); + + + + + return hzmbSwitchContentCard; // 返回创建的卡片 + } + + + + + + + + + +private BoxContentCard createddhzSwitchContentCard() { + // 创建一个可切换内容的卡片,用于显示和管理核心碰撞箱的设置 +final BoxContentCard ddhzSwitchContentCard = new BoxContentCard("定点", "绘制一个可以保存的固定红点") + .OText("定点", "绘制一个可以保存的固定红点", "Fixed point", "Draw a fixed red dot that can be saved") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +ddhzSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + + + + + + + final Text label1 = new Text() + .setText("x="+",y="+",z=") + .setTextSize(10f) + .setTextColor(0xFFC5C5C5) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(label1); + + + +final StatefulButton statefulButton1 = new StatefulButton("创建", "Create", false); + +statefulButton1.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + File langFile = new File("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + boolean isChinese = langFile.exists(); + + if (newState) { + // 开启状态 + +Fastesp.creatred(x,y,z,"id"); + statefulButton1.text.setText(isChinese ? "删除" : "Delete"); + } else { + // 关闭状态 + +Fastesp.deletered("id"); + statefulButton1.text.setText(isChinese ? "创建" : "Create"); + } + + return true; // 允许状态变化 + } +}); + +final Text shu1 = new Text() + .setText("|") + .setTextSize(15f) + .setTextColor(0xFFC5C5C5) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams().setHeight(BaseHelper.WrapContent) +); + +final RadioGroup radioGroup1 = new RadioGroup() + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + +radioGroup1.setLayoutParams(new LinearParams().setWidth(BaseHelper.MatchParent)); +radioGroup1.setEnabled(true); + +radioGroup1.addButton("获取", "Get", "1"); +radioGroup1.addButton("保存", "Save", "2"); +radioGroup1.addButton("读取", "Load", "3"); +radioGroup1.addButton("传送", "Teleport", "4"); + +// ✅ 关键:取消默认选中 +for (StatefulButton btn : radioGroup1.map.values()) { + btn.setChecked(false); +} + +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + switch (id) { + case "1"://获取 + 获取坐标(); + label1.setText("x=" + x + ",y=" + y + ",z=" + z); + break; + case "2"://保存 +检查(); + +if (!file.exists()) { + try { +file.createNewFile(); // 创建文件 +} catch (IOException e) {e.printStackTrace();} + } + +try { + + if (!dir.exists()) dir.mkdirs(); + + BufferedWriter bw = new BufferedWriter(new FileWriter(file)); + bw.write("x=" + x); + bw.newLine(); + bw.write("y=" + y); + bw.newLine(); + bw.write("z=" + z); + bw.close(); +} catch (IOException e) { + e.printStackTrace(); +} + break; + case "3"://读取 +try { + + if (file.exists()) { + BufferedReader br = new BufferedReader(new FileReader(file)); + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith("x=")) { + x = Float.parseFloat(line.substring(2).trim()); + } else if (line.startsWith("y=")) { + y = Float.parseFloat(line.substring(2).trim()); + } else if (line.startsWith("z=")) { + z = Float.parseFloat(line.substring(2).trim()); + } + } + br.close(); + } +} catch (IOException e) { + e.printStackTrace(); +} +label1.setText("x=" + x + ",y=" + y + ",z=" + z); +break; + + case "4"://传送 +//x +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList(); // 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); // 获取模块基址 +long zuobiaox = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA8; // 跳转指针 +long zuobiaoy = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA4; // 跳转指针 +long zuobiaoz = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA0; // 跳转指针 + + AlguiMemTool.setMemoryAddrValue(""+y, zuobiaoy,AlguiMemTool.TYPE_FLOAT, false,true); +AlguiMemTool.setMemoryAddrValue(""+z, zuobiaox,AlguiMemTool.TYPE_FLOAT, false,true); +AlguiMemTool.setMemoryAddrValue(""+x, zuobiaoz,AlguiMemTool.TYPE_FLOAT, false ,true); +AlguiMemTool.setMemoryAddrValue(""+y, zuobiaoy,AlguiMemTool.TYPE_FLOAT, false,true); +AlguiMemTool.setMemoryAddrValue(""+z, zuobiaox,AlguiMemTool.TYPE_FLOAT, false,true); +AlguiMemTool.setMemoryAddrValue(""+x, zuobiaoz,AlguiMemTool.TYPE_FLOAT, false ,true); + break; + } + } +}); + + +Row buttonRow1 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow1.addView(statefulButton1); + buttonRow1.addView(shu1); + buttonRow1.addView(radioGroup1); + + + + // 把这一行添加到 column 中 + column.addView(buttonRow1); + + return ddhzSwitchContentCard; // 返回创建的卡片 + } + + + + + + + + + + + + + + private enum Color { + RED(0xFFFF0000), // 红色 + GREEN(0xFF00FF00), // 绿色 + BLUE(0xFF0000FF), // 蓝色 + YELLOW(0xFFFFFF00), // 黄色 + WHITE(0xFFFFFFFF), // 白色 + BLACK(0xFF000000), // 黑色 + ORANGE(0xFFFFA500), // 橙色 + PURPLE(0xFF800080), // 紫色 + PINK(0xFFFFC0CB), // 粉色 + CYAN(0xFF00FFFF), // 青色 + MAGENTA(0xFFFF00FF), // 洋红色 + GRAY(0xFF808080); // 灰色 + + private final int value; // 存储颜色值 + + // 私有构造函数 + Color(int value) { + this.value = value; + } + + // 获取颜色值的方法 + public int getValue() { + return value; + } + } + + private enum CollisionBodyType { + ENTITY, // 实体 + PLAYER, // 角色 + PICKUP // 拾取物 + } + + // 碰撞体对象 + private static class CollisionBody { + long address; // 内存地址 + CollisionBodyType type; // 类型 + int feature1; // 特征值1 + int feature2; // 特征值2 + } + + // 绘制对象 + private static class DrawObject { + long address; // 内存地址 + Color color; // 颜色 + CollisionBodyType type; // 类型 + int dis; + int x; + int y; + } + + private static final int pSize = 8; + // 被选中对象内存地址 + private static long selectedAddr = 0; + + // 碰撞体数组地址 + static long collAddr; + + // 碰撞体数组起始地址 + static long collAddrStart; + + // 碰撞体列表 + private static CopyOnWriteArrayList collList = new + CopyOnWriteArrayList<>(); + + // 绘制对象列表 + private static ArrayList drawList = new ArrayList<>(); + + // 是否开启ESP(不是) + private static boolean espkg =true; + // 是否开启ESP("这个才是) + private static boolean zhenespkg =false; + // 是否绘制所有碰撞体 + private static boolean isDrawALLColl = false; + + // 是否绘制玩家 + private static boolean isDrawPlayer = true; + + // 是否绘制拾取物 + private static boolean isDrawPickup = false; + + // 是否绘制里准星最近目标 + private static boolean isDrawCrosshair = false; + + // 跳转指针简化方法 + public static long jump(long addr) { + return AlguiMemTool.jump(addr, pSize); + } + + // 获取数组地址 + private static boolean getArrayAddr() { + if (collAddrStart != 0) + return true; // 如果已缓存地址,直接返回成功 + + // 设置游戏包名并获取进程ID + int pid = AlguiMemTool.setPackageName("com.vortex.celestial"); + if (pid <= 0) + return false; + + // 获取模块基地址 + long module = AlguiMemTool.getModuleBaseAddr("libclient.so", AlguiMemTool.HEAD_CB); + if (module <= 0) + return false; + + // 获取碰撞体数组地址 + long collAddr = jump(module + 0xDCBC30) + 0x3C0; + if (collAddr <= 0) + return false; + + + collAddrStart = jump(collAddr); // 更新 collAddrStart 的值 + return true; // 成功获取地址 + } + + // 数组更新方法 + private static void updateArray() { + // 创建临时列表存储新数据 + ArrayList newCollList = new ArrayList<>(); + + try { + int size = Integer.parseInt(AlguiMemTool.getMemoryAddrData(collAddr + 0x2C, AlguiMemTool.TYPE_DWORD)); + + // 遍历碰撞体数组并过滤 + for (int i = 0; i < size; i++) { + CollisionBody p = new CollisionBody(); + DrawObject d = new DrawObject(); + p.address = jump(collAddrStart + i * pSize); + + // 批量读取内存数据提高性能 + p.feature1 = Integer + .parseInt(AlguiMemTool.getMemoryAddrData(p.address + 0xAC, AlguiMemTool.TYPE_DWORD)); + p.feature2 = Integer.parseInt(AlguiMemTool.getMemoryAddrData(p.address + 0x8, AlguiMemTool.TYPE_DWORD)); + + // 特征值过滤逻辑优化 + if (p.feature2 == 196614) { + if (isDrawPlayer && p.feature1 == 17039361) { + d.address = p.address; + d.color = Color.GREEN; + d.type = CollisionBodyType.PLAYER; + newCollList.add(d); + } else if (isDrawPickup && p.feature1 == 17039617) { + d.address = p.address; + d.color = Color.PURPLE; + d.type = CollisionBodyType.PICKUP; + newCollList.add(d); + } + } else if (isDrawALLColl) { + d.address = p.address; + d.color = Color.GRAY; + d.type = CollisionBodyType.ENTITY; + newCollList.add(d); + } + } + } catch (NumberFormatException e) { + return; + } + + // 替换旧列表(原子操作) + drawList.clear(); + drawList.addAll(newCollList); + + } + + // 定义一个单线程线程池,用于执行数组循环更新任务 + private static final ExecutorService arrayUpdateExecutor = Executors.newSingleThreadExecutor(); + + // 循环更新数组方法 + private static void updateArrayLoop() { + arrayUpdateExecutor.submit(new Runnable() { + @Override + public void run() { + while (zhenespkg) { + updateArray(); + try { + Thread.sleep(50); // 线程休眠50毫秒 + } catch (InterruptedException e) { + e.printStackTrace(); + Thread.currentThread().interrupt(); + break; + } + } + } + }); + } + + // 初始化绘制窗口方法 +private static AlguiWinDraw initDraw(Context context) { + + return Fastesp.start(context); +} + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/ESPCategoryBox.java.bak b/app/src/main/java/com/bytecat/algui/ui/category/ESPCategoryBox.java.bak new file mode 100644 index 0000000..85adb82 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/ESPCategoryBox.java.bak @@ -0,0 +1,663 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.graphics.Typeface; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.effect.Hint; +import java.security.Identity; +import com.bytecat.algui.ace; +import android.content.Context; +import android.app.Activity; +import java.lang.ref.WeakReference; +import irene.window.algui.Tools.HackerTool; +import irene.window.algui.MainActivity; +import java.util.concurrent.ConcurrentHashMap; +import java.io.InputStream; +import java.io.File; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import irene.window.algui.AlGuiBubbleNotification; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.bytecat.algui.ui.component.Button; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.callback.ClickCallback; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.ArrayList; +import android.os.Handler; +import com.bytecat.algui.AlguiWindows.AlguiWinInform; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import android.graphics.Paint; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import android.graphics.Canvas; +import android.view.SurfaceHolder; +import android.os.Looper; +import java.util.List; +import java.util.Map; +import java.util.Collections; +import android.view.WindowManager; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import android.graphics.Path; +import java.util.concurrent.TimeUnit; +import com.bytecat.algui.AlguiWindows.AlguiWinDraw; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.component.BoxContentCard; +import java.util.concurrent.CopyOnWriteArrayList; +import android.os.AsyncTask; +import com.bytecat.algui.effect.ArrayListView; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.effect.ColorPickerPopup; +import java.io.FileInputStream; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.BufferedWriter; +import android.graphics.PointF; +import java.util.Timer; +import java.util.TimerTask; + + + + + + +public class ESPCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + + AlguiWinDraw draw = initDraw(MIX.getContext()); + + // 保留原有的标志变量 + + + public static final long BASE_OFFSET = 0x454090; + + private static long matrixsAddr; + + + private static float readFloatFromMemory(long address) throws NumberFormatException { + if (address <= 0) { + return 0; + } + String memData = AlguiMemTool.getMemoryAddrData(address, AlguiMemTool.TYPE_FLOAT); + return Float.parseFloat(memData); + } + + + + + + + private static Activity context; + + + public static float x; +public static float y; +public static float z; + + +public static File dir = new File("/storage/emulated/0/TC配置文件/"); +public static File file = new File(dir, "coordinate1.txt"); + + + + + + + +public static void 获取坐标() { +// 1. 获取bss段基址 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long baseAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); +// 2. 多级指针跳转计算坐标地址 +long pointerPath = baseAddr + BASE_OFFSET; +long jumpAddr1 = AlguiMemTool.jump64(pointerPath); +long jumpAddr2 = AlguiMemTool.jump64(jumpAddr1 + 0x0); +long jumpAddr3 = AlguiMemTool.jump64(jumpAddr2 + 0x70); +long jumpAddr4 = AlguiMemTool.jump64(jumpAddr3 + 0x10); +long finalAddr = jumpAddr4 + 0xA0; +// 3. 设置坐标地址 +long selfZaddr = finalAddr; +long selfYaddr = selfZaddr + 0x4; +long selfXaddr = selfZaddr + 0x8; +// 4. 验证坐标值 + z = readFloatFromMemory(selfXaddr); + x = readFloatFromMemory(selfZaddr); +float y0 = readFloatFromMemory(selfYaddr); + y = y0+30; //高度高一点 +} + +public static void 检查() { +File dir = new File("/storage/emulated/0/TC配置文件/"); +if (!dir.exists()) { + dir.mkdirs(); // 创建文件夹 +} +} + + + + + public ESPCategoryBox() { + contentContainer + + +.addView(createchushSwitchContentCard()) +.addView(createhzmbSwitchContentCard()) +.addView(createddhzSwitchContentCard()) + +; + } + + + +private SwitchContentCard createchushSwitchContentCard() { + final SwitchContentCard chushSwitchContentCard = new SwitchContentCard("初始化", "初始化相关数据").OText("初始化", "初始化相关数据","Initialize","Initialize relevant data").setChecked(false); + + chushSwitchContentCard.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); +AlguiMemTool.setPackageName("com.vortex.celestial"); + if (newState) { + notification.make("绘制", "已开启","ESP","Open", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("绘制|ESP", true); + zhenespkg = true; +// 启动 +draw = Fastesp.start(context); +draw.startDraw(); + + } else { + notification.make("绘制", "已关闭","ESP","close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("绘制|ESP", false); +zhenespkg = false; +// 停止 +Fastesp.stop(); + + } + return true; + } + }); + + return chushSwitchContentCard; +} + + + + + + +private BoxContentCard createhzmbSwitchContentCard() { + // 创建一个可切换内容的卡片,用于显示和管理核心碰撞箱的设置 +final BoxContentCard hzmbSwitchContentCard = new BoxContentCard("目标", "选择绘制的目标") + .OText("目标", "选择绘制的目标", "The goal of drawing", "Select the target for drawing") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +hzmbSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + + + + final StatefulButton statefulButton = new StatefulButton("玩家","player", true); + statefulButton.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (zhenespkg) +if (newState) { +Fastesp.setDrawPlayers(true); +}else{ +Fastesp.setDrawPlayers(false); +} + + + + return true; + } + }); + + final StatefulButton statefulButton2 = new StatefulButton("物品","Article", false); + statefulButton2.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (zhenespkg) +if (newState) { +Fastesp.setDrawItems(true); +}else{ +Fastesp.setDrawItems(false); +} + return true; + } + }); + + + // 创建第一行按钮 + Row buttonRow1 = new Row(); + buttonRow1.setLayoutParams(new LinearParams().setWidth(BaseHelper.MatchParent).setHeight(BaseHelper.WrapContent) +.setTopMargin(dip2pxInt(10))); + buttonRow1.addView(statefulButton); + buttonRow1.addView(statefulButton2); + column.addView(buttonRow1); + + + + + return hzmbSwitchContentCard; // 返回创建的卡片 + } + + + + + + + + + +private BoxContentCard createddhzSwitchContentCard() { + // 创建一个可切换内容的卡片,用于显示和管理核心碰撞箱的设置 +final BoxContentCard ddhzSwitchContentCard = new BoxContentCard("定点", "绘制一个可以保存的固定红点") + .OText("定点", "绘制一个可以保存的固定红点", "Fixed point", "Draw a fixed red dot that can be saved") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) // 宽度填满父视图 + .setHeight(BaseHelper.WrapContent) // 高度自适应内容 + .setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +ddhzSwitchContentCard.setExpandableContent(column); // 将内容区域设置到卡片中 + + + + + + + final Text label1 = new Text() + .setText("x="+",y="+",z=") + .setTextSize(10f) + .setTextColor(0xFFC5C5C5) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(label1); + + + +final StatefulButton statefulButton1 = new StatefulButton("创建", "Create", false); + +statefulButton1.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + File langFile = new File("/sdcard/TC配置文件/switch.lang"); + boolean isChinese = langFile.exists(); + + if (newState) { + // 开启状态 + +Fastesp.creatred(x,y,z,"id"); + statefulButton1.text.setText(isChinese ? "删除" : "Delete"); + } else { + // 关闭状态 + +Fastesp.deletered("id"); + statefulButton1.text.setText(isChinese ? "创建" : "Create"); + } + + return true; // 允许状态变化 + } +}); + +final Text shu1 = new Text() + .setText("|") + .setTextSize(15f) + .setTextColor(0xFFC5C5C5) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams().setHeight(BaseHelper.WrapContent) +); + +final RadioGroup radioGroup1 = new RadioGroup() + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + +radioGroup1.setLayoutParams(new LinearParams().setWidth(BaseHelper.MatchParent)); +radioGroup1.setEnabled(true); + +radioGroup1.addButton("获取", "Get", "1"); +radioGroup1.addButton("保存", "Save", "2"); +radioGroup1.addButton("读取", "Load", "3"); +radioGroup1.addButton("传送", "Teleport", "4"); + +// ✅ 关键:取消默认选中 +for (StatefulButton btn : radioGroup1.map.values()) { + btn.setChecked(false); +} + +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + switch (id) { + case "1"://获取 + 获取坐标(); + label1.setText("x=" + x + ",y=" + y + ",z=" + z); + break; + case "2"://保存 +检查(); + +if (!file.exists()) { + try { +file.createNewFile(); // 创建文件 +} catch (IOException e) {e.printStackTrace();} + } + +try { + + if (!dir.exists()) dir.mkdirs(); + + BufferedWriter bw = new BufferedWriter(new FileWriter(file)); + bw.write("x=" + x); + bw.newLine(); + bw.write("y=" + y); + bw.newLine(); + bw.write("z=" + z); + bw.close(); +} catch (IOException e) { + e.printStackTrace(); +} + break; + case "3"://读取 +try { + + if (file.exists()) { + BufferedReader br = new BufferedReader(new FileReader(file)); + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith("x=")) { + x = Float.parseFloat(line.substring(2).trim()); + } else if (line.startsWith("y=")) { + y = Float.parseFloat(line.substring(2).trim()); + } else if (line.startsWith("z=")) { + z = Float.parseFloat(line.substring(2).trim()); + } + } + br.close(); + } +} catch (IOException e) { + e.printStackTrace(); +} +label1.setText("x=" + x + ",y=" + y + ",z=" + z); +break; + + case "4"://传送 +//x +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList(); // 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); // 获取模块基址 +long zuobiaox = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA8; // 跳转指针 +long zuobiaoy = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA4; // 跳转指针 +long zuobiaoz = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA0; // 跳转指针 + + AlguiMemTool.setMemoryAddrValue(""+y, zuobiaoy,AlguiMemTool.TYPE_FLOAT, false,true); +AlguiMemTool.setMemoryAddrValue(""+z, zuobiaox,AlguiMemTool.TYPE_FLOAT, false,true); +AlguiMemTool.setMemoryAddrValue(""+x, zuobiaoz,AlguiMemTool.TYPE_FLOAT, false ,true); +AlguiMemTool.setMemoryAddrValue(""+y, zuobiaoy,AlguiMemTool.TYPE_FLOAT, false,true); +AlguiMemTool.setMemoryAddrValue(""+z, zuobiaox,AlguiMemTool.TYPE_FLOAT, false,true); +AlguiMemTool.setMemoryAddrValue(""+x, zuobiaoz,AlguiMemTool.TYPE_FLOAT, false ,true); + break; + } + } +}); + + +Row buttonRow1 = new Row() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + + buttonRow1.addView(statefulButton1); + buttonRow1.addView(shu1); + buttonRow1.addView(radioGroup1); + + + + // 把这一行添加到 column 中 + column.addView(buttonRow1); + + return ddhzSwitchContentCard; // 返回创建的卡片 + } + + + + + + + + + + + + + + private enum Color { + RED(0xFFFF0000), // 红色 + GREEN(0xFF00FF00), // 绿色 + BLUE(0xFF0000FF), // 蓝色 + YELLOW(0xFFFFFF00), // 黄色 + WHITE(0xFFFFFFFF), // 白色 + BLACK(0xFF000000), // 黑色 + ORANGE(0xFFFFA500), // 橙色 + PURPLE(0xFF800080), // 紫色 + PINK(0xFFFFC0CB), // 粉色 + CYAN(0xFF00FFFF), // 青色 + MAGENTA(0xFFFF00FF), // 洋红色 + GRAY(0xFF808080); // 灰色 + + private final int value; // 存储颜色值 + + // 私有构造函数 + Color(int value) { + this.value = value; + } + + // 获取颜色值的方法 + public int getValue() { + return value; + } + } + + private enum CollisionBodyType { + ENTITY, // 实体 + PLAYER, // 角色 + PICKUP // 拾取物 + } + + // 碰撞体对象 + private static class CollisionBody { + long address; // 内存地址 + CollisionBodyType type; // 类型 + int feature1; // 特征值1 + int feature2; // 特征值2 + } + + // 绘制对象 + private static class DrawObject { + long address; // 内存地址 + Color color; // 颜色 + CollisionBodyType type; // 类型 + int dis; + int x; + int y; + } + + private static final int pSize = 8; + // 被选中对象内存地址 + private static long selectedAddr = 0; + + // 碰撞体数组地址 + static long collAddr; + + // 碰撞体数组起始地址 + static long collAddrStart; + + // 碰撞体列表 + private static CopyOnWriteArrayList collList = new + CopyOnWriteArrayList<>(); + + // 绘制对象列表 + private static ArrayList drawList = new ArrayList<>(); + + // 是否开启ESP(不是) + private static boolean espkg =true; + // 是否开启ESP("这个才是) + private static boolean zhenespkg =false; + // 是否绘制所有碰撞体 + private static boolean isDrawALLColl = false; + + // 是否绘制玩家 + private static boolean isDrawPlayer = true; + + // 是否绘制拾取物 + private static boolean isDrawPickup = false; + + // 是否绘制里准星最近目标 + private static boolean isDrawCrosshair = false; + + // 跳转指针简化方法 + public static long jump(long addr) { + return AlguiMemTool.jump(addr, pSize); + } + + // 获取数组地址 + private static boolean getArrayAddr() { + if (collAddrStart != 0) + return true; // 如果已缓存地址,直接返回成功 + + // 设置游戏包名并获取进程ID + int pid = AlguiMemTool.setPackageName("com.vortex.celestial"); + if (pid <= 0) + return false; + + // 获取模块基地址 + long module = AlguiMemTool.getModuleBaseAddr("libclient.so", AlguiMemTool.HEAD_CB); + if (module <= 0) + return false; + + // 获取碰撞体数组地址 + long collAddr = jump(module + 0xDCBC30) + 0x3C0; + if (collAddr <= 0) + return false; + + + collAddrStart = jump(collAddr); // 更新 collAddrStart 的值 + return true; // 成功获取地址 + } + + // 数组更新方法 + private static void updateArray() { + // 创建临时列表存储新数据 + ArrayList newCollList = new ArrayList<>(); + + try { + int size = Integer.parseInt(AlguiMemTool.getMemoryAddrData(collAddr + 0x2C, AlguiMemTool.TYPE_DWORD)); + + // 遍历碰撞体数组并过滤 + for (int i = 0; i < size; i++) { + CollisionBody p = new CollisionBody(); + DrawObject d = new DrawObject(); + p.address = jump(collAddrStart + i * pSize); + + // 批量读取内存数据提高性能 + p.feature1 = Integer + .parseInt(AlguiMemTool.getMemoryAddrData(p.address + 0xAC, AlguiMemTool.TYPE_DWORD)); + p.feature2 = Integer.parseInt(AlguiMemTool.getMemoryAddrData(p.address + 0x8, AlguiMemTool.TYPE_DWORD)); + + // 特征值过滤逻辑优化 + if (p.feature2 == 196614) { + if (isDrawPlayer && p.feature1 == 17039361) { + d.address = p.address; + d.color = Color.GREEN; + d.type = CollisionBodyType.PLAYER; + newCollList.add(d); + } else if (isDrawPickup && p.feature1 == 17039617) { + d.address = p.address; + d.color = Color.PURPLE; + d.type = CollisionBodyType.PICKUP; + newCollList.add(d); + } + } else if (isDrawALLColl) { + d.address = p.address; + d.color = Color.GRAY; + d.type = CollisionBodyType.ENTITY; + newCollList.add(d); + } + } + } catch (NumberFormatException e) { + return; + } + + // 替换旧列表(原子操作) + drawList.clear(); + drawList.addAll(newCollList); + + } + + // 定义一个单线程线程池,用于执行数组循环更新任务 + private static final ExecutorService arrayUpdateExecutor = Executors.newSingleThreadExecutor(); + + // 循环更新数组方法 + private static void updateArrayLoop() { + arrayUpdateExecutor.submit(new Runnable() { + @Override + public void run() { + while (zhenespkg) { + updateArray(); + try { + Thread.sleep(50); // 线程休眠50毫秒 + } catch (InterruptedException e) { + e.printStackTrace(); + Thread.currentThread().interrupt(); + break; + } + } + } + }); + } + + // 初始化绘制窗口方法 +private static AlguiWinDraw initDraw(Context context) { + + return Fastesp.start(context); +} + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/EspDataCache.java b/app/src/main/java/com/bytecat/algui/ui/category/EspDataCache.java new file mode 100644 index 0000000..185fed6 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/EspDataCache.java @@ -0,0 +1,16 @@ +package com.bytecat.algui.ui.category; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +public final class EspDataCache { + public static final class Entity { + public float x, y, z; + public int typeFlag; + } + + public static volatile CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + + // 原来的 list 继续留着,但只用来遍历 +public static final ConcurrentHashMap map = new ConcurrentHashMap<>(); +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/EspFetcherThread.java b/app/src/main/java/com/bytecat/algui/ui/category/EspFetcherThread.java new file mode 100644 index 0000000..6e63b68 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/EspFetcherThread.java @@ -0,0 +1,96 @@ +package com.bytecat.algui.ui.category; + +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public final class EspFetcherThread extends Thread { + private volatile boolean running = true; + + private long matrixAddr; + private long collAddr; + private long collStart; + + public EspFetcherThread(long matrixAddr, long collAddr, long collStart) { + this.matrixAddr = matrixAddr; + this.collAddr = collAddr; + this.collStart = collStart; + setPriority(Thread.MIN_PRIORITY); // 降低调度压力 + } + + public void stopSafely() { + running = false; + interrupt(); + } + +@Override +public void run() { + final float[] matrix = new float[16]; + while (running) { + try { + // 1. 读矩阵 + for (int i = 0; i < 16; i++) { + matrix[i] = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(matrixAddr + i * 4, AlguiMemTool.TYPE_FLOAT)); + } + + // 2. 读实体数量 + int count = Integer.parseInt( + AlguiMemTool.getMemoryAddrData(collAddr + 0x2C, AlguiMemTool.TYPE_DWORD)); + if (count <= 0 || count > 2048) { + Thread.sleep(8); + continue; + } + + // 3. 记录本帧存在的地址 + Set aliveThisFrame = new HashSet(); + + for (int i = 0; i < count; i++) { + long addr = AlguiMemTool.jump64(collStart + i * 8); + if (addr == 0) continue; + + int typeFlag = Integer.parseInt( + AlguiMemTool.getMemoryAddrData(addr + 0xAC, AlguiMemTool.TYPE_DWORD)); + int flag2 = Integer.parseInt( + AlguiMemTool.getMemoryAddrData(addr + 0x8, AlguiMemTool.TYPE_DWORD)); + if (flag2 != 196614) continue; + + aliveThisFrame.add(addr); + + // 如果 map 里没有就新建 + EspDataCache.Entity e = EspDataCache.map.get(addr); + if (e == null) { + e = new EspDataCache.Entity(); + EspDataCache.map.put(addr, e); + } + + // 更新坐标 + e.x = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(addr + 0xA0, AlguiMemTool.TYPE_FLOAT)); + e.z = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(addr + 0xA4, AlguiMemTool.TYPE_FLOAT)); + e.y = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(addr + 0xA8, AlguiMemTool.TYPE_FLOAT)); + e.typeFlag = typeFlag; + } + + // 4. 删除已消失的实体(传统迭代器写法) + Iterator it = EspDataCache.map.keySet().iterator(); + while (it.hasNext()) { + long addr = it.next(); + if (!aliveThisFrame.contains(addr)) { + it.remove(); + } + } + + // 5. 把 map 同步到 list(供绘制) + EspDataCache.list.clear(); + EspDataCache.list.addAll(EspDataCache.map.values()); + + Thread.sleep(16); + } catch (Exception ignored) {} + } +} + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/Fastesp.java b/app/src/main/java/com/bytecat/algui/ui/category/Fastesp.java new file mode 100644 index 0000000..e3f4d82 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/Fastesp.java @@ -0,0 +1,510 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.PorterDuff; +import android.graphics.Typeface; +import android.view.MotionEvent; +import android.view.SurfaceHolder; +import android.view.View; +import android.widget.FrameLayout; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import com.bytecat.algui.AlguiWindows.AlguiWinDraw; +import com.bytecat.algui.ui.MIX; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class Fastesp { + + // ... 其他代码保持不变 ... + + private static AlguiWinDraw draw; // 声明静态变量 draw + + private static EspFetcherThread fetcher; + public static long moduleBase, matrixAddr, collAddr, collStart; + public static final float[] matrix = new float[16]; + private static int midX, midY; + public static int fii = 5; + private static volatile boolean running = false; + + // 增加玩家和物品的开关控制 + private static boolean drawPlayers = true; + private static boolean drawItems = false; + + // 三维红点相关 + private static final ConcurrentHashMap redPoints = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap redPointsWorldX = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap redPointsWorldY = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap redPointsWorldZ = new ConcurrentHashMap<>(); + + public static AlguiWinDraw start(Context ctx) { + if (ctx == null) ctx = MIX.getContext(); + if (ctx == null) + throw new IllegalStateException("Context 为 null,请先初始化 MIX 或传入 Activity!"); + running = true; + draw = buildDraw(ctx); // 初始化 draw + return draw; + } + +private static final int MODE_JOY = 0; // 摇杆模式 +private static final int MODE_MOVE = 1; // 移动模式 +private static int mode = MODE_JOY; // 当前模式 +private static long lastDownTime = 0; // 用于双击判断 +private static final int DOUBLE_TAP_TIMEOUT = 300; // ms +// 摇杆当前输出向量 [-1,1] +public static float joystickX; +public static float joystickY; +// 是否正在用摇杆 +public static boolean isJoystickMove; +// ================== 摇杆控件 ================== +private static class JoystickView extends View { + /* ==== 基本尺寸 ==== */ + private float baseX, baseY; // 摇杆底座中心(可拖动) + private float bigR, smallR; + private float knobX, knobY; // 摇杆钮当前位置 + private Paint bgPaint, knobPaint; + + /* ==== 触摸状态 ==== */ + private boolean draggingKnob = false; // 是否在拖拽摇杆钮 + private boolean draggingBase = false; // 是否在拖动底座 + private float lastTouchX, lastTouchY; + + public JoystickView(Context c) { + super(c); + bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + bgPaint.setColor(Color.argb(120, 0, 0, 0)); + knobPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + knobPaint.setColor(Color.argb(200, 0, 200, 255)); + + // 初始位置:左下角 + bigR = dp(60); + smallR = dp(25); + baseX = bigR + dp(20); + baseY = getResources().getDisplayMetrics().heightPixels - bigR - dp(20); + knobX = baseX; + knobY = baseY; + } + + private float dp(int px) { + return getResources().getDisplayMetrics().density * px; + } + + /* ==== 绘制 ==== */ + @Override protected void onDraw(Canvas canvas) { + canvas.drawCircle(baseX, baseY, bigR, bgPaint); + canvas.drawCircle(knobX, knobY, smallR, knobPaint); + } + + /* ==== 触摸 ==== */ + @SuppressLint("ClickableViewAccessibility") + @Override public boolean onTouchEvent(MotionEvent e) { + float x = e.getX(); + float y = e.getY(); + + switch (e.getAction()) { + case MotionEvent.ACTION_DOWN: + // 双击检测 + if (System.currentTimeMillis() - lastDownTime < DOUBLE_TAP_TIMEOUT) { + toggleMode(); + lastDownTime = 0; // 防止三连击 + return true; + } + lastDownTime = System.currentTimeMillis(); + + if (mode == MODE_MOVE) { + // 移动模式:只要按在底座内就可以拖动整个摇杆 + if (dist(x, y, baseX, baseY) <= bigR) { + draggingBase = true; + lastTouchX = x; + lastTouchY = y; + } + } else { + // 摇杆模式:只有按在底座内才能拖动小钮 + if (dist(x, y, baseX, baseY) <= bigR) { + draggingKnob = true; + moveKnob(x, y); + } + } + break; + + case MotionEvent.ACTION_MOVE: + if (draggingBase) { + baseX += x - lastTouchX; + baseY += y - lastTouchY; + knobX = baseX; + knobY = baseY; + lastTouchX = x; + lastTouchY = y; + invalidate(); + } else if (draggingKnob) { + moveKnob(x, y); + } + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + draggingKnob = false; + draggingBase = false; + // 松手回中 + knobX = baseX; + knobY = baseY; + invalidate(); + break; + } + return true; + } + + private void toggleMode() { + mode = (mode == MODE_JOY) ? MODE_MOVE : MODE_JOY; + invalidate(); + } + + private void moveKnob(float x, float y) { + float dx = x - baseX; + float dy = y - baseY; + float len = (float) Math.sqrt(dx * dx + dy * dy); + if (len > bigR) { + dx = dx / len * bigR; + dy = dy / len * bigR; + } + knobX = baseX + dx; + knobY = baseY + dy; + invalidate(); +// 在 JoystickView.moveKnob() 末尾加一行 +Fastesp.joystickX = dx / bigR; // 已归一化 +Fastesp.joystickY = -dy / bigR; // 屏幕坐标系转游戏坐标系 +Fastesp.isJoystickMove = draggingKnob; + /* TODO: 如果需要把摇杆向量输出出去,可以在这里回调 + float vx = dx / bigR; + float vy = -dy / bigR; + */ + } + + private float dist(float x1, float y1, float x2, float y2) { + return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + } +} + + + + + +/* 专门给路径记录用的红点,旁边固定写“路径点” */ +public static void createPathPoint(float x, float y, float z, String id) { + redPointsWorldX.put(id, x); + redPointsWorldY.put(id, y); + redPointsWorldZ.put(id, z); +} +// ============================================= + + +private static JoystickView joystick; + +private static Thread moveThread; +private static volatile boolean moveRunning; + +public static void startMoveThread() { + if (moveThread != null) return; + moveRunning = true; +moveThread = new Thread(new Runnable() { + @Override + public void run() { + /* ↓↓↓ 原来花括号里的代码全部原封不动搬进来 ↓↓↓ */ + int pid = AlguiMemTool.getPID("com.vortex.celestial"); + if (pid < 0) return; + + long libClient = AlguiMemTool.getModuleBaseAddr("libclient.so", AlguiMemTool.HEAD_CB); + if (libClient == 0) return; + + long matrixAddr = AlguiMemTool.jump64( + AlguiMemTool.jump64( + AlguiMemTool.jump64( + AlguiMemTool.jump64(libClient + 0x45A228) + 0x268) + 0xE0) + 0x40); + + long oneselfBase = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(libClient + 0x454090) + 0x0) + 0x70) + 0x10; // 跳转指针 + + while (moveRunning) { + try { + if (!isJoystickMove) { + Thread.sleep(20); + continue; + } + + float[] m = new float[16]; + for (int i = 0; i < 16; i++) { + m[i] = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(matrixAddr + i * 4, AlguiMemTool.TYPE_FLOAT)); + } + + float x = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(oneselfBase + 0xA0, AlguiMemTool.TYPE_FLOAT)); + float z = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(oneselfBase + 0xA4, AlguiMemTool.TYPE_FLOAT)); + float y = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(oneselfBase + 0xA8, AlguiMemTool.TYPE_FLOAT)); + + float dirX = m[2]; + float dirZ = m[6]; + float dirY = m[10]; + float len = (float) Math.sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); + dirX /= len; + dirZ /= len; + dirY /= len; + + float moveScale = 5.0f; + x += dirX * joystickY * moveScale; + z += dirZ * joystickY * moveScale * 2; + y += dirY * joystickY * moveScale; + + float rightX = m[0]; + float rightZ = m[4]; + float rightY = m[8]; + len = (float) Math.sqrt(rightX * rightX + rightY * rightY + rightZ * rightZ); + rightX /= len; + rightZ /= len; + rightY /= len; + + x += rightX * joystickX * moveScale; + z += rightZ * joystickX * moveScale * 2; + y += rightY * joystickX * moveScale; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(x), oneselfBase + 0xA0, AlguiMemTool.TYPE_FLOAT, false, true); + AlguiMemTool.setMemoryAddrValue(String.valueOf(z), oneselfBase + 0xA4, AlguiMemTool.TYPE_FLOAT, false, true); + AlguiMemTool.setMemoryAddrValue(String.valueOf(y), oneselfBase + 0xA8, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(20); + } catch (Exception ignore) { } + } + } +}); +moveThread.start(); + +} + +public static void stopMoveThread() { + moveRunning = false; + if (moveThread != null) { + moveThread.interrupt(); + moveThread = null; + } +} + + + +public static void showJoystick(Activity act) { + if (joystick != null) return; + FrameLayout root = act.findViewById(android.R.id.content); + joystick = new JoystickView(act); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT); + root.addView(joystick, lp); +} + +public static void hideJoystick(Activity act) { + if (joystick == null) return; + FrameLayout root = act.findViewById(android.R.id.content); + root.removeView(joystick); + joystick = null; +} + +public static void stop() { + running = false; // 1. 让下一次 Update() 直接 return + + // 2. 立即清屏 + if (draw != null) { + Canvas canvas = null; + try { + canvas = draw.getHolder().lockCanvas(); // 尝试锁定当前 Surface + if (canvas != null) { + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // 清屏 + } + } catch (Exception ignore) { + // 防止 Surface 已被销毁时崩溃 + } finally { + if (canvas != null) { + draw.getHolder().unlockCanvasAndPost(canvas); // 确保解锁 + } + draw.endRendering(); // 如果有额外释放动作 + } + } + + // 3. 清空数据 + redPointsWorldX.clear(); + redPointsWorldY.clear(); + redPointsWorldZ.clear(); +if (fetcher != null) { + fetcher.stopSafely(); + fetcher = null; +} +} + + + // 设置玩家绘制开关 + public static void setDrawPlayers(boolean enable) { + drawPlayers = enable; + } + + // 设置物品绘制开关 + public static void setDrawItems(boolean enable) { + drawItems = enable; + } + + // 创建一个三维红点 + public static void creatred(float x, float y, float z, String id) { + redPointsWorldX.put(id, x); + redPointsWorldY.put(id, y); + redPointsWorldZ.put(id, z); + } + + // 删除特定 ID 的三维红点 + public static void deletered(String id) { + if ("allred".equals(id)) { + redPointsWorldX.clear(); + redPointsWorldY.clear(); + redPointsWorldZ.clear(); + } else { + redPointsWorldX.remove(id); + redPointsWorldY.remove(id); + redPointsWorldZ.remove(id); + } + } + + private static AlguiWinDraw buildDraw(Context ctx) { + final Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setTextSize(18); + paint.setColor(Color.WHITE); + paint.setTextAlign(Paint.Align.CENTER); + paint.setTypeface(Typeface.DEFAULT_BOLD); + paint.setShadowLayer(4, 0, 0, Color.BLACK); + + final Paint linePaint = new Paint(); + linePaint.setAntiAlias(true); + linePaint.setStrokeWidth(2f); + + final AlguiWinDraw draw = new AlguiWinDraw(ctx); + draw.setCatCallback(new AlguiCallback.Draw() { + long lastFrame = 0; + private long moduleBase = 0; + private long matrixAddr = 0; + private long collAddr = 0; + private long collStart = 0; + private final float[] matrix = new float[16]; + private int screenW = 0, screenH = 0; + private int midX = 0; + + private long jump(long addr) { + return AlguiMemTool.jump64(addr); + } + + @Override + public boolean Start(Canvas canvas) { + if (moduleBase == 0) { + moduleBase = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); +if (moduleBase == 0) return false; +matrixAddr =AlguiMemTool.jump64( + AlguiMemTool.jump64( + AlguiMemTool.jump64( + AlguiMemTool.jump64(moduleBase + 0x45A228) + 0x268) + 0xE0) + 0x40); +collAddr = jump(moduleBase + 0xDCBC30) + 0x3C0; +collStart = jump(collAddr); + } + +fetcher = new EspFetcherThread(matrixAddr, collAddr, collStart); +fetcher.start(); + return matrixAddr > 0 && collStart > 0; + } +@Override +public boolean Update(Canvas canvas) { + long now = System.currentTimeMillis(); + if (now - lastFrame < fii) return true; + lastFrame = now; + + // 1. 重新读矩阵(仍放在主线程,极快) + for (int i = 0; i < matrix.length; i++) { + matrix[i] = Float.parseFloat( + AlguiMemTool.getMemoryAddrData(matrixAddr + i * 4, AlguiMemTool.TYPE_FLOAT)); + } + + // 2. 玩家数量(可选) + if (drawPlayers) { + int total = 0; + for (EspDataCache.Entity e : EspDataCache.list) + if (e.typeFlag == 17039361) total++; + paint.setColor(Color.GREEN); + canvas.drawText("玩家数量: " + total, 80, 40, paint); + } + + // 3. 绘制实体(从缓存拿数据) + for (EspDataCache.Entity e : EspDataCache.list) { + if ((e.typeFlag == 17039361 && !drawPlayers) || + (e.typeFlag != 17039361 && !drawItems)) continue; + +// 计算 cz(距离因子) +float cz = matrix[3] * e.x + matrix[7] * e.z + matrix[11] * e.y + matrix[15]; +if (cz <= 0) continue; // 距离为负数或零 → 不绘制 + + + float cx = midX + (matrix[0] * e.x + matrix[4] * e.z + matrix[8] * e.y + matrix[12]) / cz * midX; + float cy = midY - (matrix[1] * e.x + matrix[5] * e.z + matrix[9] * e.y + matrix[13]) / cz * midY; + + int color = e.typeFlag == 17039361 ? 0xFF00FF00 : 0xFFFF00FF; + linePaint.setColor(color); + canvas.drawLine(midX, 0, cx, cy, linePaint); + paint.setColor(color); + canvas.drawText((e.typeFlag == 17039361 ? "玩家 " : "物品 ") + (int)(cz/60), (int)cx, (int)cy, paint); + } + + + // 绘制三维红点...(后续代码保持不变) + final Paint redPaint = new Paint(); + redPaint.setColor(Color.RED); + redPaint.setStyle(Paint.Style.FILL); + + for (String id : new ConcurrentHashMap<>(redPointsWorldX).keySet()) { + Float x = redPointsWorldX.get(id); + Float y = redPointsWorldY.get(id); + Float z = redPointsWorldZ.get(id); + + if (x == null || y == null || z == null) continue; + + float cz = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15]; + if (cz <= 2) continue; + + float cx = midX + (matrix[0] * x + matrix[4] * y + matrix[8] * z + matrix[12]) / cz * midX; + float cy = midY - (matrix[1] * x + matrix[5] * y + matrix[9] * z + matrix[13]) / cz * midY; + + canvas.drawCircle(cx, cy, 12, redPaint); + canvas.drawText("坐标", cx + 20, cy, paint); + } + + // 4. 红点/路径保持原样,无需改动 + // ...(保留你原来代码)... + return true; +} + @Override + public void End(SurfaceHolder holder) {} + + @Override + public void UpdateCanvasSize(SurfaceHolder holder, int format, int width, int height) { + screenW = width; + screenH = height; + midX = width / 2; + midY = height / 2; + } + }); + return draw; + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/FileUtilT.java b/app/src/main/java/com/bytecat/algui/ui/category/FileUtilT.java new file mode 100644 index 0000000..82bbac7 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/FileUtilT.java @@ -0,0 +1,48 @@ +package com.bytecat.algui.ui.category; // ← 换成你自己的包名 + +import java.io.*; + +public final class FileUtilT { + + /** 递归复制整个目录 */ + public static void copyDir(File src, File dst) throws IOException { + if (src == null || !src.exists()) return; + if (src.isFile()) { // 如果传进来的 src 是单个文件 + copyFile(src, dst); + return; + } + dst.mkdirs(); + File[] list = src.listFiles(); + if (list == null) return; + for (File f : list) { + File target = new File(dst, f.getName()); + if (f.isDirectory()) { + copyDir(f, target); + } else { + copyFile(f, target); + } + } + } + + /** 复制单个文件 */ + private static void copyFile(File src, File dst) throws IOException { + try (FileInputStream in = new FileInputStream(src); + FileOutputStream out = new FileOutputStream(dst)) { + byte[] buf = new byte[8192]; + int len; + while ((len = in.read(buf)) != -1) out.write(buf, 0, len); + } + } + + /** 递归删除文件 / 文件夹 */ + public static void deleteRecursive(File f) { + if (f == null || !f.exists()) return; + if (f.isDirectory()) { + File[] children = f.listFiles(); + if (children != null) for (File c : children) deleteRecursive(c); + } + f.delete(); + } + + private FileUtilT() {} // 禁止实例化 +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/MiscCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/MiscCategoryBox.java new file mode 100644 index 0000000..527dd19 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/MiscCategoryBox.java @@ -0,0 +1,682 @@ +package com.bytecat.algui.ui.category; + +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import android.graphics.Typeface; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.callback.SliderCallback; +import android.annotation.SuppressLint; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.ace; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.effect.Notification; +import java.util.Locale; +import com.bytecat.algui.effect.ModuleManager; + + +public class MiscCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + + + +//快捷键 +private SwitchShortcutButton zlxsShortcutButton; +private SwitchShortcutButton whzlShortcutButton; +private SwitchShortcutButton syzfShortcutButton; +private SwitchShortcutButton sxjgdShortcutButton; +private SwitchShortcutButton qzzlShortcutButton; +private SwitchShortcutButton gzghShortcutButton; +private SwitchShortcutButton wxhjShortcutButton; + + + + +//卡片 + public MiscCategoryBox() { + createShortcutButtons(); + contentContainer + +.addView(createwhzlSwitchContentCard()) +.addView(createsyzfSwitchContentCard()) +.addView(createsxjgdSwitchContentCard()) +.addView(createqzzlSwitchContentCard()) +.addView(creategzghSwitchContentCard()) +.addView(createwxhjSwitchContentCard()) + + + + + + ; + } + + +//快捷键文本 + private void createShortcutButtons() { +whzlShortcutButton = new SwitchShortcutButton() +.OText("视角稳定器","Stabilizer"); +syzfShortcutButton = new SwitchShortcutButton().OText("视野","FOV"); +sxjgdShortcutButton = new SwitchShortcutButton().OText("摄像机","Camera"); +qzzlShortcutButton = new SwitchShortcutButton().OText("帧率","FPS"); +gzghShortcutButton = new SwitchShortcutButton().OText("改装光环","Halo"); +wxhjShortcutButton = new SwitchShortcutButton().OText("无序挥击","Disorder"); + + + } + + + + +private SwitchContentCard createwhzlSwitchContentCard() { + final SwitchContentCard whzlSwitchContentCard = new SwitchContentCard("视角稳定器", "减小后坐力对视角的影响").OText("视角稳定器","减小后坐力对视角的影响","Stabilizer","Reduce the impact of recoil on the view").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + whzlSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + whzlShortcutButton.show(); + } else { + whzlShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(whzlSwitchContentCard, whzlShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("视角稳定器", "已开启", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("视角稳定器|Stabilizer", true); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCDE218) + 0x78) + 0xE8) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_DOUBLE, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("视角稳定器", "已关闭", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("视角稳定器|Stabilizer", false); + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCDE218) + 0x78) + 0xE8) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("55", daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return whzlSwitchContentCard; + } + + + +private SwitchContentCard createsyzfSwitchContentCard() { + final SwitchContentCard syzfSwitchContentCard = new SwitchContentCard("视野修改", "修改视野大小").OText("视野大小","修改视野大小","FOV","Adjust the field of view").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + syzfSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("数值: ") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("0.5") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(2, 0.1f, 0.5f) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcef50)+0xf8)+0x58)+0x1f0)+0x7a0)+0x178;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcef50)+0xf8)+0x58)+0x1f0)+0x7a0)+0x178;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + syzfShortcutButton.show(); + } else { + syzfShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(syzfSwitchContentCard, syzfShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + + + + + +ModuleManager.getInstance().setModuleEnabled("视野修改|Visual field", true); + + } else { + + ModuleManager.getInstance().setModuleEnabled("视野修改|Visual field", false); + distanceText.setText("1.0"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcef50)+0xf8)+0x58)+0x1f0)+0x7a0)+0x178;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return syzfSwitchContentCard; + } + + + + + +private SwitchContentCard createsxjgdSwitchContentCard() { + final SwitchContentCard sxjgdSwitchContentCard = new SwitchContentCard("摄像机高度", "修改摄像机高度").OText("摄像机高度","修改摄像机高度","Camera high","Adjust the camera height").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + sxjgdSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("数值: ") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(1, -2, 0) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCD0C10)+0x2B8)+0x110)+0x80)+0x58)+0x114;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCD0C10)+0x2B8)+0x110)+0x80)+0x58)+0x114;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + sxjgdShortcutButton.show(); + } else { + sxjgdShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(sxjgdSwitchContentCard, sxjgdShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + + +ModuleManager.getInstance().setModuleEnabled("摄像机高度|Camera height", true); + + + } else { + + ModuleManager.getInstance().setModuleEnabled("摄像机高度|Camera height", false); + distanceText.setText("0"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCD0C10)+0x2B8)+0x110)+0x80)+0x58)+0x114;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-0.1", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return sxjgdSwitchContentCard; + } + + + + + + private SwitchContentCard createqzzlSwitchContentCard() { + final SwitchContentCard qzzlSwitchContentCard = new SwitchContentCard("强制帧率", "强制修改144帧率").OText("强制帧率","强制修改144帧率","FPS","Force modification of high frame rate").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + qzzlSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + qzzlShortcutButton.show(); + } else { + qzzlShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(qzzlSwitchContentCard, qzzlShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + + notification.make("强制帧率", "已开启", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("强制帧率|Frame rate", true); + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0x600) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 +// 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("144", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("强制帧率", "已关闭", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("强制帧率|Frame rate", false); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0x600) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 +// 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("60", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return qzzlSwitchContentCard; + } + + + +private SwitchContentCard creategzghSwitchContentCard() { + final SwitchContentCard gzghSwitchContentCard = new SwitchContentCard("改装光环", "改装状态下携带光环移动").OText("改装光环","改装状态下携带光环移动","Halo","Carry Halo Mobile").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + gzghSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + gzghShortcutButton.show(); + } else { + gzghShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(gzghSwitchContentCard, gzghShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("改装光环", "已开启", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("改装光环|Halo", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x800)+ 0x538) + 0x528) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("08521", daddr, AlguiMemTool.TYPE_DWORD, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("改装光环", "切换画质以关闭功能", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("改装光环|Halo", false); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x800)+ 0x538) + 0x528) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("689273856", daddr, AlguiMemTool.TYPE_DWORD, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } + return true; + } + }); + + return gzghSwitchContentCard; + } + +private SwitchContentCard createwxhjSwitchContentCard() { + final SwitchContentCard wxhjSwitchContentCard = new SwitchContentCard("无序挥击", "[仅自己可见]所有可旋转模块无序转动").OText("无序挥击","[仅自己可见]所有可旋转模块无序转动","Disorder","All rotatable modules rotate disorderly").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + wxhjSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + wxhjShortcutButton.show(); + } else { + wxhjShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(wxhjSwitchContentCard, wxhjShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("无序挥击", "已开启", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("无序挥击|Disorder", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x7C0)+ 0x7B0) + 0x608) + 0x7E4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9999", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("无序挥击", "已关闭", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("无序挥击|Disorder", false); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x7C0)+ 0x7B0) + 0x608) + 0x7E4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-185", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return wxhjSwitchContentCard; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/MiscCategoryBox.java.bak b/app/src/main/java/com/bytecat/algui/ui/category/MiscCategoryBox.java.bak new file mode 100644 index 0000000..c657bba --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/MiscCategoryBox.java.bak @@ -0,0 +1,682 @@ +package com.bytecat.algui.ui.category; + +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import android.graphics.Typeface; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.callback.SliderCallback; +import android.annotation.SuppressLint; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.ace; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.effect.Notification; +import java.util.Locale; +import com.bytecat.algui.effect.ModuleManager; + + +public class MiscCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + + + +//快捷键 +private SwitchShortcutButton zlxsShortcutButton; +private SwitchShortcutButton whzlShortcutButton; +private SwitchShortcutButton syzfShortcutButton; +private SwitchShortcutButton sxjgdShortcutButton; +private SwitchShortcutButton qzzlShortcutButton; +private SwitchShortcutButton gzghShortcutButton; +private SwitchShortcutButton wxhjShortcutButton; + + + + +//卡片 + public MiscCategoryBox() { + createShortcutButtons(); + contentContainer + +.addView(createwhzlSwitchContentCard()) +.addView(createsyzfSwitchContentCard()) +.addView(createsxjgdSwitchContentCard()) +.addView(createqzzlSwitchContentCard()) +.addView(creategzghSwitchContentCard()) +.addView(createwxhjSwitchContentCard()) + + + + + + ; + } + + +//快捷键文本 + private void createShortcutButtons() { +whzlShortcutButton = new SwitchShortcutButton() +.OText("视角稳定器","Stabilizer"); +syzfShortcutButton = new SwitchShortcutButton().OText("视野","FOV"); +sxjgdShortcutButton = new SwitchShortcutButton().OText("摄像机","Camera"); +qzzlShortcutButton = new SwitchShortcutButton().OText("帧率","Frame rate"); +gzghShortcutButton = new SwitchShortcutButton().OText("改装光环","Halo"); +wxhjShortcutButton = new SwitchShortcutButton().OText("无序挥击","Disorder"); + + + } + + + + +private SwitchContentCard createwhzlSwitchContentCard() { + final SwitchContentCard whzlSwitchContentCard = new SwitchContentCard("视角稳定器", "减小后坐力对视角的影响").OText("视角稳定器","减小后坐力对视角的影响","Stabilizer","Reduce the impact of recoil on the view").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + whzlSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + whzlShortcutButton.show(); + } else { + whzlShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(whzlSwitchContentCard, whzlShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("视角稳定器", "已开启", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("视角稳定器|Stabilizer", true); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCDE218) + 0x78) + 0xE8) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_DOUBLE, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("视角稳定器", "已关闭", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("视角稳定器|Stabilizer", false); + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCDE218) + 0x78) + 0xE8) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("55", daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return whzlSwitchContentCard; + } + + + +private SwitchContentCard createsyzfSwitchContentCard() { + final SwitchContentCard syzfSwitchContentCard = new SwitchContentCard("视野修改", "修改视野大小").OText("视野大小","修改视野大小","FOV","Adjust the field of view").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + syzfSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("数值: ") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("0.5") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(2, 0.1f, 0.5f) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcef50)+0xf8)+0x58)+0x1f0)+0x7a0)+0x178;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcef50)+0xf8)+0x58)+0x1f0)+0x7a0)+0x178;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + syzfShortcutButton.show(); + } else { + syzfShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(syzfSwitchContentCard, syzfShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + + + + + +ModuleManager.getInstance().setModuleEnabled("视野修改|Visual field", true); + + } else { + + ModuleManager.getInstance().setModuleEnabled("视野修改|Visual field", false); + distanceText.setText("1.0"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcef50)+0xf8)+0x58)+0x1f0)+0x7a0)+0x178;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return syzfSwitchContentCard; + } + + + + + +private SwitchContentCard createsxjgdSwitchContentCard() { + final SwitchContentCard sxjgdSwitchContentCard = new SwitchContentCard("摄像机高度", "修改摄像机高度").OText("摄像机高度","修改摄像机高度","Camera high","Adjust the camera height").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + sxjgdSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("数值: ") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(1, -2, 0) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCD0C10)+0x2B8)+0x110)+0x80)+0x58)+0x114;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCD0C10)+0x2B8)+0x110)+0x80)+0x58)+0x114;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + sxjgdShortcutButton.show(); + } else { + sxjgdShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(sxjgdSwitchContentCard, sxjgdShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + + +ModuleManager.getInstance().setModuleEnabled("摄像机高度|Camera height", true); + + + } else { + + ModuleManager.getInstance().setModuleEnabled("摄像机高度|Camera height", false); + distanceText.setText("0"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCD0C10)+0x2B8)+0x110)+0x80)+0x58)+0x114;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-0.1", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return sxjgdSwitchContentCard; + } + + + + + + private SwitchContentCard createqzzlSwitchContentCard() { + final SwitchContentCard qzzlSwitchContentCard = new SwitchContentCard("强制帧率", "强制修改144帧率").OText("强制帧率","强制修改144帧率","Frame rate","Force modification of high frame rate").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + qzzlSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + qzzlShortcutButton.show(); + } else { + qzzlShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(qzzlSwitchContentCard, qzzlShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + + notification.make("强制帧率", "已开启", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("强制帧率|Frame rate", true); + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0x600) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 +// 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("144", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("强制帧率", "已关闭", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("强制帧率|Frame rate", false); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0x600) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 +// 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("60", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return qzzlSwitchContentCard; + } + + + +private SwitchContentCard creategzghSwitchContentCard() { + final SwitchContentCard gzghSwitchContentCard = new SwitchContentCard("改装光环", "改装状态下携带光环移动").OText("改装光环","改装状态下携带光环移动","Halo","Carry Halo Mobile").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + gzghSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + gzghShortcutButton.show(); + } else { + gzghShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(gzghSwitchContentCard, gzghShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("改装光环", "已开启", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("改装光环|Halo", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x800)+ 0x538) + 0x528) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("08521", daddr, AlguiMemTool.TYPE_DWORD, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("改装光环", "切换画质以关闭功能", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("改装光环|Halo", false); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x800)+ 0x538) + 0x528) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("689273856", daddr, AlguiMemTool.TYPE_DWORD, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } + return true; + } + }); + + return gzghSwitchContentCard; + } + +private SwitchContentCard createwxhjSwitchContentCard() { + final SwitchContentCard wxhjSwitchContentCard = new SwitchContentCard("无序挥击", "[仅自己可见]所有可旋转模块无序转动").OText("无序挥击","[仅自己可见]所有可旋转模块无序转动","Disorder","All rotatable modules rotate disorderly").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + wxhjSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + wxhjShortcutButton.show(); + } else { + wxhjShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(wxhjSwitchContentCard, wxhjShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("无序挥击", "已开启", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("无序挥击|Disorder", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x7C0)+ 0x7B0) + 0x608) + 0x7E4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9999", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("无序挥击", "已关闭", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("无序挥击|Disorder", false); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x7C0)+ 0x7B0) + 0x608) + 0x7E4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-185", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return wxhjSwitchContentCard; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/PlayerCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/PlayerCategoryBox.java new file mode 100644 index 0000000..1ab4a72 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/PlayerCategoryBox.java @@ -0,0 +1,2768 @@ +package com.bytecat.algui.ui.category; + +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import android.graphics.Typeface; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.callback.SliderCallback; +import android.annotation.SuppressLint; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ace; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.File; +import java.util.Locale; +import java.util.concurrent.Delayed; +import android.os.AsyncTask; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.time.Clock; +import com.bytecat.algui.ui.component.ButtonContent; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.button.ShortcutButton; +import android.view.View; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.AlguiHacker.AlguiNativeMemTool; + +public class PlayerCategoryBox extends CategoryBox { + private SwitchShortcutButton jsShortcutButton; + private SwitchShortcutButton gjShortcutButton; + private SwitchShortcutButton xzShortcutButton; + private SwitchShortcutButton hzlShortcutButton; + private SwitchShortcutButton tkShortcutButton; +private SwitchShortcutButton tytkShortcutButton; +private SwitchShortcutButton hzkxShortcutButton; +private SwitchShortcutButton wjfsShortcutButton; +private SwitchShortcutButton hwbdShortcutButton; +private SwitchShortcutButton jxmcShortcutButton; +private SwitchShortcutButton jjxtShortcutButton; +private SwitchShortcutButton dlsjsShortcutButton; +private SwitchShortcutButton sjzkShortcutButton; +private SwitchShortcutButton kqzlShortcutButton; +private SwitchShortcutButton zlxgShortcutButton; + private ShortcutButton shunShortcutButton; + private SwitchShortcutButton zzShortcutButton; + private SwitchShortcutButton zzzShortcutButton; + private SwitchShortcutButton xxShortcutButton; + private SwitchShortcutButton xxxShortcutButton; + private SwitchShortcutButton yyShortcutButton; + private SwitchShortcutButton yyyShortcutButton; + private SwitchShortcutButton yjShortcutButton; + private SwitchShortcutButton gdShortcutButton; + private SwitchShortcutButton djzzShortcutButton; + + + + public PlayerCategoryBox() { + createShortcutButtons(); + contentContainer + + .addView(createsjSwitchContentCard()) + .addView(createtkSwitchContentCard()) + .addView(createtytkSwitchContentCard()) + .addView(createsjzkSwitchContentCard()) + .addView(createxzSwitchContentCard()) + .addView(createhzlSwitchContentCard()) + .addView(createhzkxSwitchContentCard()) + .addView(createwjfsSwitchContentCard()) + .addView(createhwbdSwitchContentCard()) + .addView(createjxmcSwitchContentCard()) + .addView(createjjxtSwitchContentCard()) + .addView(createkqzlSwitchContentCard()) + .addView(createzlxgSwitchContentCard()) + .addView(createzzSwitchContentCard()) + .addView(createSwitchContentCard()) + .addView(createdlsjsSwitchContentCard()) + ; + + } + private void createShortcutButtons() { + + gjShortcutButton = new SwitchShortcutButton() + .OText("阻力修改","Modifyresistan"); + xzShortcutButton = new SwitchShortcutButton() + .OText("旋转","Rotate"); + hzlShortcutButton = new SwitchShortcutButton() + .OText("后坐力","Recoil"); +hzkxShortcutButton = new SwitchShortcutButton() + .OText("后坐力抗性","Resist"); +wjfsShortcutButton = new SwitchShortcutButton() + .OText("无迹飞梭","Spacebounce"); +hwbdShortcutButton = new SwitchShortcutButton() + .OText("恒稳不倒","Notfall"); +jxmcShortcutButton = new SwitchShortcutButton() + .OText("减小摩擦","Friction"); +jjxtShortcutButton = new SwitchShortcutButton() + .OText("紧急固定","Emergencyfixation"); + dlsjsShortcutButton = new SwitchShortcutButton() + .OText("推进加速","Acceleration"); +sjzkShortcutButton = new SwitchShortcutButton() + .OText("视角自控","Self-control"); +kqzlShortcutButton = new SwitchShortcutButton() + .OText("空气阻力","Airfriction"); + tkShortcutButton = new SwitchShortcutButton() + .OText("核心踏空","Fly"); + tytkShortcutButton = new SwitchShortcutButton() + .OText("腾跃踏空","Airjump"); + zlxgShortcutButton = new SwitchShortcutButton() + .OText("重力调节","Gravity"); + + xxShortcutButton = new SwitchShortcutButton() + .OText("[纵]Y+","Y++"); + xxxShortcutButton = new SwitchShortcutButton() + .OText("[纵]Y-","Y--"); + yyShortcutButton = new SwitchShortcutButton() + .OText("[横]X+","X++"); + yyyShortcutButton = new SwitchShortcutButton() + .OText("[横]X-","X--"); + zzShortcutButton = new SwitchShortcutButton() + .setText("Z++"); + zzzShortcutButton = new SwitchShortcutButton() + .setText("Z--"); + yjShortcutButton = new SwitchShortcutButton() + .OText("坐标控制","TP"); + gdShortcutButton = new SwitchShortcutButton() + .OText("冻结高度","freeze"); + djzzShortcutButton = new SwitchShortcutButton() + .OText("锁定坐标","lock"); + + } + + private SwitchContent shortcutSwitchContent; +Notification notification = Notification.getInstance(); + +private AsyncTask asyncTask; + + private AsyncTask asyncTask1; + private AsyncTask asyncTask2; + + private Thread thread1; + private Thread thread2; + private volatile boolean isRunning = true; // 添加一个标志变量,用于控制循环是否继续执行 + private ExecutorService executorService; + private Thread task1Thread = null; + private Thread task2Thread = null; + private Thread task3Thread = null; + private Thread task4Thread = null; + private Thread task5Thread = null; + private Thread task6Thread = null; + + + + /* ====== 控制线程 ====== */ + private volatile Thread flyThread = null; + private volatile boolean running = false; + + /* ====== 自控速度 ====== */ + private float flySpeed; // 默认速度 + + + private SwitchContentCard createsjSwitchContentCard() { + final SwitchContentCard reachSwitchContentCard = new SwitchContentCard("阻力修改", "改变游戏中对于玩家的综合阻力").OText("阻力修改","改变游戏中对于玩家的综合阻力","Modifyresistan","Modify and set resistance").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + reachSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + Text distanceTitleText = new Text() + .setText("数值: ","Value:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("9.55") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(10, 0, 9) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText.setText(String.format(""+newProgress)); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x380868) + 0x400) + 0x55A;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format("%.2f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x380868) + 0x400) + 0x55A;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + gjShortcutButton.show(); + } else { + gjShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(reachSwitchContentCard, gjShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + +ModuleManager.getInstance().setModuleEnabled("阻力修改|Modifyresistan", true); + // 创建线程并启动 + + + + } else { + ModuleManager.getInstance().setModuleEnabled("阻力修改|Modifyresistan", false); + distanceText.setText("9.55"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x380868) + 0x400) + 0x55A;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9.5", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return reachSwitchContentCard; + } + + + +private SwitchContentCard createxzSwitchContentCard() { + final SwitchContentCard xzSwitchContentCard = new SwitchContentCard("车体旋转", "车体快速自转").OText("车体旋转","车体快速自转","Rotate","Rapid rotation").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + xzSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + xzShortcutButton.show(); + } else { + xzShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(xzSwitchContentCard, xzShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { +Main.音效(); + if (newState) { +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xE4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("969.37", daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setFreezeDelayMs(20); +ModuleManager.getInstance().setModuleEnabled("车体旋转|Rotate", true); + + + } else { +ModuleManager.getInstance().setModuleEnabled("车体旋转|Rotate", false); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xE4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("969.37", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setFreezeDelayMs(20); + } + return true; + } + }); + + return xzSwitchContentCard; + } + + + +private SwitchContentCard createhzlSwitchContentCard() { + final SwitchContentCard hzlSwitchContentCard = new SwitchContentCard("后坐力", "修改并设置武器的后坐力").OText("后坐力","修改并设置武器的后坐力","Recoil","Change and set the recoil of the weapon").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + hzlSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("反向: ","Reverse direction:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("-3.5") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(10, -10, -3) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + if (newProgress<0) { + distanceTitleText.setText("反向:","Reverse direction:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + AlguiMemTool.setFreezeDelayMs(0); + } + + + + if (newProgress ==0) { + distanceTitleText.setText("暂不支持","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + } + + if (newProgress>0) { + distanceTitleText.setText("正向:","Positive Direction:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + + + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + + + AlguiMemTool.setFreezeDelayMs(0); + } + if (newProgress!=0) { + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + AlguiMemTool.setFreezeDelayMs(0); + } + +} + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + AlguiMemTool.setFreezeDelayMs(0); + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + hzlShortcutButton.show(); + } else { + hzlShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(hzlSwitchContentCard, hzlShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + +ModuleManager.getInstance().setModuleEnabled("后坐力|Recoil", true); + + + + } else { + + ModuleManager.getInstance().setModuleEnabled("后坐力|Recoil", false); + distanceText.setText("无"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + AlguiMemTool.setFreezeDelayMs(0); + } + return true; + } + }); + + return hzlSwitchContentCard; + } + + + + + + + + +private SwitchContentCard createsjzkSwitchContentCard() { + final SwitchContentCard sjzkSwitchContentCard = new SwitchContentCard("视角自控", "向视角朝向飞行") + .OText("视角自控","向视角朝向飞行","Self-controlled flight","Towards the perspective towards flight"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + sjzkSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能") + .OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + sjzkShortcutButton.show(); + } else { + sjzkShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + + SyncUtil.sync(sjzkSwitchContentCard, sjzkShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + notification.make("视角自控", "已开启", "Self-controlled flight", "Open", Notification.Type.SUCCESS); + ModuleManager.getInstance().setModuleEnabled("视角自控|Self-controlled flight", true); + +ace.executeHiddenBinary("libalguivv.so"); + + } else { + notification.make("视角自控", "已关闭", "Self-controlled flight", "Close", Notification.Type.ERROR); + ModuleManager.getInstance().setModuleEnabled("视角自控|Self-controlled flight", false); + +ace.stopBinary("libalguivv.so"); + } + return true; + } + }); + + return sjzkSwitchContentCard; +} + + + + private SwitchContentCard createzzSwitchContentCard() { + + final SwitchContentCard yjSwitchContentCard = new SwitchContentCard("坐标控制", "根据不同的需求进行坐标级平移").OText("坐标控制台","根据不同的数值进行坐标轴平移","Coordinates","Coordinate Control Console").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + yjSwitchContentCard.setExpandableContent(column); + + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("X轴 [地图上横向]:","X:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(10000, -10000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr2, AlguiMemTool.TYPE_FLOAT, false, true); + AlguiMemTool.setFreezeDelayMs(0); + + } + } + + }); + column.addView(slider); + + Row distanceRow1 = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow1); + + final Text distanceTitleText1 = new Text() + .setText("Y轴 [地图上纵向]:","Y:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow1.addView(distanceTitleText1); + + final Text distanceText1 = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow1.addView(distanceText1); + + final Slider slider1 = new Slider(10000, -10000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText1.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText1.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + } + + }); + column.addView(slider1); + + Row distanceRow2 = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow2); + + final Text distanceTitleText2 = new Text() + .setText("Z轴 [人物高度]:","Z").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow2.addView(distanceTitleText2); + + final Text distanceText2 = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow2.addView(distanceText2); + + final Slider slider2 = new Slider(10000, -1000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText2.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText2.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + } + + }); + column.addView(slider2); + + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + + xxShortcutButton.show(); + xxxShortcutButton.show(); + yyShortcutButton.show(); + yyyShortcutButton.show(); + gdShortcutButton.show(); + djzzShortcutButton.show(); + zzShortcutButton.show(); + zzzShortcutButton.show(); + } else { + + xxShortcutButton.dismiss(); + xxxShortcutButton.dismiss(); + yyShortcutButton.dismiss(); + yyyShortcutButton.dismiss(); + gdShortcutButton.dismiss(); + djzzShortcutButton.dismiss(); + zzzShortcutButton.dismiss(); + zzShortcutButton.dismiss(); + stopTask2(); + stopTask1(); + stopTask3(); + stopTask4(); + gdShortcutButton.setChecked(false); + xxShortcutButton.setChecked(false); + xxxShortcutButton.setChecked(false); + yyShortcutButton.setChecked(false); + yyyShortcutButton.setChecked(false); + djzzShortcutButton.setChecked(false); + zzShortcutButton.setChecked(false); + zzzShortcutButton.setChecked(false); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(yjSwitchContentCard, yjShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); + slider1.setEnabled(newState); + slider1.setEnabled1(newState); + slider2.setEnabled(newState); + slider2.setEnabled1(newState); +Main.音效(); + if (newState) { +ModuleManager.getInstance().setModuleEnabled("坐标控制|Coordinates", true); + + + } else { +ModuleManager.getInstance().setModuleEnabled("坐标控制|Coordinates", false); + + } + return true; + } + }); + + xxShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked) { + if (isChecked) { + + startTask1(); + } else { + stopTask1(); + } + return true; // 允许状态切换 + } + }); + xxxShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked1) { + if (isChecked1) { + startTask3(); + + } else { + stopTask3(); + } + return true; // 允许状态切换 + } + }); + + yyShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked2) { + if (isChecked2) { + startTask2(); + + } else { + stopTask2(); + } + return true; // 允许状态切换 + } + }); + + yyyShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked3) { + if (isChecked3) { + startTask4(); + + } else { + stopTask4(); + } + return true; // 允许状态切换 + } + }); + + zzShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked4) { + if (isChecked4) { + startTask5(); + + } else { + stopTask5(); + } + return true; // 允许状态切换 + } + }); + + zzzShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked3) { + if (isChecked3) { + startTask6(); + + } else { + stopTask6(); + } + return true; // 允许状态切换 + } + }); + + gdShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked3) { + if (isChecked3) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue, daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + AlguiMemTool.setFreezeDelayMs(0); + } + return true; // 允许状态切换 + } + }); + + djzzShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked3) { + if (isChecked3) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue, daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + + String currentValue1 = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue1, daddr, AlguiMemTool.TYPE_FLOAT, true, true); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + + String currentValue2 = AlguiMemTool.getMemoryAddrData(daddr2, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue2, daddr2, AlguiMemTool.TYPE_FLOAT, true, true); + + + + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + + String currentValue1 = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue1, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + + String currentValue2 = AlguiMemTool.getMemoryAddrData(daddr2, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue2, daddr2, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + return true; // 允许状态切换 + } + }); + + return yjSwitchContentCard; + } + + private SwitchContentCard createtkSwitchContentCard() { + final SwitchContentCard tkSwitchContentCard = new SwitchContentCard("核心踏空", "使萌新核心可踏空行走").OText("核心踏空","使核心可以踏空行走","Fly","Make it possible to step on the air after disassembly"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + tkSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("数值: ","Value:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("1.0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(1024, 1, 512) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +// 设置包名 + + +// + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x288) + 0x0E8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x288) + 0x0E8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + tkShortcutButton.show(); + } else { + tkShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(tkSwitchContentCard, tkShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + +ModuleManager.getInstance().setModuleEnabled("核心踏空|Fly", true); + + } else { + + ModuleManager.getInstance().setModuleEnabled("核心踏空|Fly", false); + + distanceText.setText("1.0"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x288) + 0x0E8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("0.85", daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return tkSwitchContentCard; + } + +private SwitchContentCard createtytkSwitchContentCard() { + final SwitchContentCard tytkSwitchContentCard = new SwitchContentCard("腾跃踏空", "使有腾跃模块的铁臂可踏空行走").OText("腾跃踏空","装上腾跃即可踏空而行","AirJump","Fly for me."); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + tytkSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("数值: ","Value:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("5.0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(500, 2, 5) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + tytkShortcutButton.show(); + } else { + tytkShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(tytkSwitchContentCard, tytkShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + + +ModuleManager.getInstance().setModuleEnabled("腾越踏空|AirJump", true); + + } else { + +ModuleManager.getInstance().setModuleEnabled("腾越踏空|AirJump", false); + distanceText.setText("0.85"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0.85", daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return tytkSwitchContentCard; + } + + + + + + +private SwitchContentCard createhzkxSwitchContentCard() { + final SwitchContentCard hzkxSwitchContentCard = new SwitchContentCard("后坐力抗性", "减少后坐力对玩家的影响,但会导致行动会缓慢").OText("后坐力抗性","减少后坐力对玩家的影响,但会导致行动会缓慢","Resist","Reducing the impact of recoil on players"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + hzkxSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + hzkxShortcutButton.show(); + } else { + hzkxShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(hzkxSwitchContentCard, hzkxShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { +Main.音效(); + if (newState) { +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x456E28)+0x150)+0x40)+0x88)+0x70)+0xFC;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("17", daddr1, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x1A8)+0xFC;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("17", daddr21, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + +ModuleManager.getInstance().setModuleEnabled("后坐力抗性|Resist", true); + + } else { + +ModuleManager.getInstance().setModuleEnabled("后坐力抗性|Resist", false); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x456E28)+0x150)+0x40)+0x88)+0x70)+0xFC;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr1, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x1A8)+0xFC;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr21, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + return true; + } + }); + + return hzkxSwitchContentCard; + } + + + + + + + +private SwitchContentCard createwjfsSwitchContentCard() { + final SwitchContentCard wjfsSwitchContentCard = new SwitchContentCard("无迹飞梭", "毫无轨迹的后坐力移动方式").OText("无迹飞梭","毫无轨迹的后坐力移动方式","Spacebounce","Flight mode without trajectory"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + wjfsSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + wjfsShortcutButton.show(); + } else { + wjfsShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(wjfsSwitchContentCard, wjfsShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { +Main.音效(); + if (newState) { +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30)+0x10)+0x750)+0x78)+0x430)+0xC8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-869", daddr1, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x70)+0xC8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-869", daddr21, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + +ModuleManager.getInstance().setModuleEnabled("无迹飞梭|Spacebounce", true); + + + + } else { +ModuleManager.getInstance().setModuleEnabled("无迹飞梭|Spacebounce", true); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30)+0x10)+0x750)+0x78)+0x430)+0xC8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr1, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x70)+0xC8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr21, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + return true; + } + }); + + return wjfsSwitchContentCard; + } + + + + + private ButtonContentCard createSwitchContentCard() { + final ButtonContentCard zzbutton = new ButtonContentCard("一键自杀", "传送到深渊", false) + .OText("一键自杀", "传送到深渊", "One-Click Suicide", "Teleport to Abyss") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + + + zzbutton.setClickCallback(new ClickCallback() { + @Override + public void onClick() { + 自杀(); + } + }); + + + + return zzbutton; +} + + + + + + private SwitchContentCard createhwbdSwitchContentCard() { + final SwitchContentCard hwbdSwitchContentCard = new SwitchContentCard("恒稳不倒", "玩家保持垂直于地面的稳定姿态,不会倒下").OText("恒稳不倒","玩家保持垂直于地面的稳定姿态,不会倒下","Nofall","Won't fall."); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + hwbdSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + hwbdShortcutButton.show(); + } else { + hwbdShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(hwbdSwitchContentCard, hwbdShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("恒稳不倒", "已开启","Nofall","Open", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("恒稳不倒|Nofall", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x4602C0) + 0xC0) + 0x60) + + 0x10) + 0x1A8) + 0xAC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x0;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x8;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr3, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool + .jump64(AlguiMemTool.jump64(AlguiMemTool + .jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(sAddr21 + 0xD274F8) + 0x168) + 0x340) + + 0x80) + 0xA0) + + 0x98;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("恒稳不倒", "已关闭","Nofall","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("恒稳不倒|Nofall", false); + + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x4602C0) + 0xC0) + 0x60) + + 0x10) + 0x1A8) + 0xAC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x0;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x8;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr3, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool + .jump64(AlguiMemTool.jump64(AlguiMemTool + .jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(sAddr21 + 0xD274F8) + 0x168) + 0x340) + + 0x80) + 0xA0) + + 0x98;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } + return true; + } + }); + + return hwbdSwitchContentCard; + } + + + +private SwitchContentCard createjxmcSwitchContentCard() { + final SwitchContentCard jxmcSwitchContentCard = new SwitchContentCard("减小摩擦", "减小与地面的摩擦力").OText("减少摩擦","减小与地面的摩擦力","Friction","Reduce friction with the ground"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + jxmcSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + jxmcShortcutButton.show(); + } else { + jxmcShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(jxmcSwitchContentCard, jxmcShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("减小摩擦", "已开启","Friction","Open", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("减小摩擦|Friction", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + + 0x88) + 0x15C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x380868) + 0x28) + 0x0) + + 0x88) + 0xA0) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x456E28) + 0x150) + 0x40) + + 0x88) + 0x40) + 0x15C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr3, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool + .jump64(AlguiMemTool.jump64(AlguiMemTool + .jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(sAddr21 + 0x39F028) + 0x3D0) + 0x138) + + 0x88) + 0x88) + + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("减小摩擦", "已关闭","Friction","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("减小摩擦|Friction", false); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + + 0x88) + 0x15C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x380868) + 0x28) + 0x0) + + 0x88) + 0xA0) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x456E28) + 0x150) + 0x40) + + 0x88) + 0x40) + 0x15C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr3, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool + .jump64(AlguiMemTool.jump64(AlguiMemTool + .jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(sAddr21 + 0x39F028) + 0x3D0) + 0x138) + + 0x88) + 0x88) + + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } + return true; + } + }); + + return jxmcSwitchContentCard; + } + + +private SwitchContentCard createjjxtSwitchContentCard() { + final SwitchContentCard jjxtSwitchContentCard = new SwitchContentCard("紧急固定", "紧急固定车体坐标").OText("紧急固定","紧急固定车体的坐标","Emergencyfixation","Emergency fixed coordinate"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + jjxtSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + jjxtShortcutButton.show(); + } else { + jjxtShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(jjxtSwitchContentCard, jjxtShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + + if (newState) { + notification.make("紧急固定", "已开启","Emergencyfixation","Open", Notification.Type.SUCCESS); + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + + 0xA0) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9399.08521", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + +ModuleManager.getInstance().setModuleEnabled("紧急固定|Emergencyfixation", true); + } else { + ModuleManager.getInstance().setModuleEnabled("紧急固定|Emergencyfixation", false); + notification.make("紧急固定", "已关闭","Emergencyfixation","Close", Notification.Type.ERROR); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + + 0xA0) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + return true; + } + }); + + return jjxtSwitchContentCard; + } + + private SwitchContentCard createkqzlSwitchContentCard() { + final SwitchContentCard kqzlSwitchContentCard = new SwitchContentCard("空气阻力", "增加空气阻力").OText("空气阻力","增加空气阻力","Airfriction","Increase the resistance of the air"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + kqzlSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + kqzlShortcutButton.show(); + } else { + kqzlShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(kqzlSwitchContentCard, kqzlShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("空气阻力", "已开启","Airfriction","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("空气阻力|Airfriction", true); + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCA3520)+0x50)+0x300)+0x1E8)+0x10)+0xF8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30)+0x388)+0x0)+0x88)+0x38)+0x68;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr1, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + + + } else { +notification.make("空气阻力", "已关闭","Airfriction","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("空气阻力|Airfriction", false); + + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCA3520)+0x50)+0x300)+0x1E8)+0x10)+0xF8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30)+0x388)+0x0)+0x88)+0x38)+0x68;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr1, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return kqzlSwitchContentCard; + } + + +private SwitchContentCard createzlxgSwitchContentCard() { + final SwitchContentCard zlxgSwitchContentCard = new SwitchContentCard("重力调节", "修改人物重力").OText("重力调节","修改人物重力","Gravity","Change one's own gravity"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + zlxgSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("数值: ","Value:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(3, -3, 0) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcbc30)+0x3f8)+0x420)+0x28)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xdcbc30)+0x358)+0x440)+0x10)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr1, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcbc30)+0x3f8)+0x420)+0x28)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xdcbc30)+0x358)+0x440)+0x10)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + zlxgShortcutButton.show(); + } else { + zlxgShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(zlxgSwitchContentCard, zlxgShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + +ModuleManager.getInstance().setModuleEnabled("重力调节|Gravity", true); + + notification.make("重力调节", "已开启","Gravity","Open", Notification.Type.SUCCESS); + + + + } else { + +ModuleManager.getInstance().setModuleEnabled("重力调节|Gravity", false); + notification.make("重力调节", "已关闭","Gravity","Close", Notification.Type.ERROR); + distanceText.setText("0"); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcbc30)+0x3f8)+0x420)+0x28)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xdcbc30)+0x358)+0x440)+0x10)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr1, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return zlxgSwitchContentCard; + } + + + + +private SwitchContentCard createdlsjsSwitchContentCard() { + final SwitchContentCard dlsjsSwitchContentCard = new SwitchContentCard("推进加速","增加大力神速度").OText("推进加速","增加大力神速度","Propeller acceleration","Speed up the accelerator"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + dlsjsSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("数值: ","Value:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("1.875") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(9, 2, 2) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + +distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc69248)+0x328)+0x3c0)+0x180)+0x44;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc69248)+0x328)+0x3c0)+0x180)+0x44;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + } + + }); + column.addView(slider); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + + + + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + dlsjsShortcutButton.show(); + } else { + dlsjsShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(dlsjsSwitchContentCard, dlsjsShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + + if (newState) { + notification.make("推进加速", "已开启","Propeller acceleration","Open", Notification.Type.SUCCESS); + + + +ModuleManager.getInstance().setModuleEnabled("推进加速|Propeller acceleration", true); + } else { + ModuleManager.getInstance().setModuleEnabled("推进加速|Propeller acceleration", false); + notification.make("推进加速", "已关闭","Propeller acceleration","Close", Notification.Type.ERROR); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc69248)+0x328)+0x3c0)+0x180)+0x44;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1.875", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + AlguiMemTool.setMemoryAddrValue("1.875", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + return true; + } + }); + + return dlsjsSwitchContentCard; + } + + + + + + + + + + + + + + + + + + + + + + + + + + +private void 自杀() { + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( +AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDCBC30) + 0x380) + 0x1C0)+ 0x88) + 0x38) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-114000", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( +AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30) + 0x380) + 0x1C0)+ 0x88) + 0x38) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-114000", daddr1, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + +notification.make("一键自杀", "执行", Notification.Type.SUCCESS); + +} + + + + + + + + + + private void executeBehavior(String selectedOption, boolean enable) { + if (enable) { + ace.executeHiddenBinary(getAction(selectedOption)); // 添加行为到数组 + } else { + ace.executeHiddenBinary(getCloseAction(selectedOption)); + } + } + + private String getAction(String option) { + switch (option) { + + case"1": + + return "1"; + case"3": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("9", daddr, AlguiMemTool.TYPE_DOUBLE, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + return "3"; + case"4": + return "4"; + + + default: + return "ONE"; + }} + private String getCloseAction(String option) { + switch (option) { + case "1": + return "1"; + case "option2": + return "行为2关闭"; + case "option3": + return "行为3关闭"; + default: + return "行为1关闭"; + }} + + + + + + + + + + + // 创建一个固定大小的线程池,这里使用 2 个线程 + + + private Runnable task1Logic = new Runnable() { + @Override + public void run() { + try { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + AlguiMemTool.setMemoryAddrValue("2000", daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue + 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + // 封装任务2的逻辑 + private Runnable task2Logic = new Runnable() { + @Override + public void run() { + try { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + AlguiMemTool.setMemoryAddrValue("2000", daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue + 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + private Runnable task3Logic = new Runnable() { + @Override + public void run() { + try { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + AlguiMemTool.setMemoryAddrValue("2000", daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue - 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + private Runnable task4Logic = new Runnable() { + @Override + public void run() { + try { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + AlguiMemTool.setMemoryAddrValue("2000", daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue - 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + + private Runnable task5Logic = new Runnable() { + @Override + public void run() { + try { + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue + 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + private Runnable task6Logic = new Runnable() { + @Override + public void run() { + try { + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue - 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + + + + // 启动任务1 + public void startTask1() { + if (task1Thread == null || !task1Thread.isAlive()) { + task1Thread = new Thread(task1Logic); + task1Thread.start(); + } + } + + // 启动任务2 + public void startTask2() { + if (task2Thread == null || !task2Thread.isAlive()) { + task2Thread = new Thread(task2Logic); + task2Thread.start(); + } + } + + public void startTask3() { + if (task3Thread == null || !task3Thread.isAlive()) { + task3Thread = new Thread(task3Logic); + task3Thread.start(); + } + } + + public void startTask4() { + if (task4Thread == null || !task4Thread.isAlive()) { + task4Thread = new Thread(task4Logic); + task4Thread.start(); + } + } + + public void startTask5() { + if (task5Thread == null || !task5Thread.isAlive()) { + task5Thread = new Thread(task5Logic); + task5Thread.start(); + } + } + + public void startTask6() { + if (task6Thread == null || !task6Thread.isAlive()) { + task6Thread = new Thread(task6Logic); + task6Thread.start(); + } + } + + // 停止任务1 + public void stopTask1() { + if (task1Thread != null && task1Thread.isAlive()) { + task1Thread.interrupt(); // 中断线程 + } + } + + // 停止任务2 + public void stopTask2() { + if (task2Thread != null && task2Thread.isAlive()) { + task2Thread.interrupt(); // 中断线程 + } + } + + public void stopTask3() { + if (task3Thread != null && task3Thread.isAlive()) { + task3Thread.interrupt(); // 中断线程 + } + } + + public void stopTask4() { + if (task4Thread != null && task4Thread.isAlive()) { + task4Thread.interrupt(); // 中断线程 + } + } + + + public void stopTask5() { + if (task5Thread != null && task5Thread.isAlive()) { + task5Thread.interrupt(); // 中断线程 + } + } + + public void stopTask6() { + if (task6Thread != null && task6Thread.isAlive()) { + task6Thread.interrupt(); // 中断线程 + } + } + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/PlayerCategoryBox.java.bak b/app/src/main/java/com/bytecat/algui/ui/category/PlayerCategoryBox.java.bak new file mode 100644 index 0000000..ad525b8 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/PlayerCategoryBox.java.bak @@ -0,0 +1,2766 @@ +package com.bytecat.algui.ui.category; + +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import android.graphics.Typeface; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.callback.SliderCallback; +import android.annotation.SuppressLint; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ace; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.File; +import java.util.Locale; +import java.util.concurrent.Delayed; +import android.os.AsyncTask; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.time.Clock; +import com.bytecat.algui.ui.component.ButtonContent; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.button.ShortcutButton; +import android.view.View; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.AlguiHacker.AlguiNativeMemTool; + +public class PlayerCategoryBox extends CategoryBox { + private SwitchShortcutButton jsShortcutButton; + private SwitchShortcutButton gjShortcutButton; + private SwitchShortcutButton xzShortcutButton; + private SwitchShortcutButton hzlShortcutButton; + private SwitchShortcutButton tkShortcutButton; +private SwitchShortcutButton tytkShortcutButton; +private SwitchShortcutButton hzkxShortcutButton; +private SwitchShortcutButton wjfsShortcutButton; +private SwitchShortcutButton hwbdShortcutButton; +private SwitchShortcutButton jxmcShortcutButton; +private SwitchShortcutButton jjxtShortcutButton; +private SwitchShortcutButton dlsjsShortcutButton; +private SwitchShortcutButton sjzkShortcutButton; +private SwitchShortcutButton kqzlShortcutButton; +private SwitchShortcutButton zlxgShortcutButton; + private ShortcutButton shunShortcutButton; + private SwitchShortcutButton zzShortcutButton; + private SwitchShortcutButton zzzShortcutButton; + private SwitchShortcutButton xxShortcutButton; + private SwitchShortcutButton xxxShortcutButton; + private SwitchShortcutButton yyShortcutButton; + private SwitchShortcutButton yyyShortcutButton; + private SwitchShortcutButton yjShortcutButton; + private SwitchShortcutButton gdShortcutButton; + private SwitchShortcutButton djzzShortcutButton; + + + + public PlayerCategoryBox() { + createShortcutButtons(); + contentContainer + + .addView(createsjSwitchContentCard()) + .addView(createtkSwitchContentCard()) + .addView(createtytkSwitchContentCard()) + .addView(createsjzkSwitchContentCard()) + .addView(createxzSwitchContentCard()) + .addView(createhzlSwitchContentCard()) + .addView(createhzkxSwitchContentCard()) + .addView(createwjfsSwitchContentCard()) + .addView(createhwbdSwitchContentCard()) + .addView(createjxmcSwitchContentCard()) + .addView(createjjxtSwitchContentCard()) + .addView(createkqzlSwitchContentCard()) + .addView(createzlxgSwitchContentCard()) + .addView(createzzSwitchContentCard()) + .addView(createSwitchContentCard()) + .addView(createdlsjsSwitchContentCard()) + ; + + } + private void createShortcutButtons() { + + gjShortcutButton = new SwitchShortcutButton() + .OText("阻力修改","Modifyresistan"); + xzShortcutButton = new SwitchShortcutButton() + .OText("旋转","Rotate"); + hzlShortcutButton = new SwitchShortcutButton() + .OText("后坐力","Recoil"); +hzkxShortcutButton = new SwitchShortcutButton() + .OText("后坐力抗性","Resist"); +wjfsShortcutButton = new SwitchShortcutButton() + .OText("无迹飞梭","Spacebounce"); +hwbdShortcutButton = new SwitchShortcutButton() + .OText("恒稳不倒","Notfall"); +jxmcShortcutButton = new SwitchShortcutButton() + .OText("减小摩擦","Friction"); +jjxtShortcutButton = new SwitchShortcutButton() + .OText("紧急固定","Emergencyfixation"); + dlsjsShortcutButton = new SwitchShortcutButton() + .OText("推进加速","Acceleration"); +sjzkShortcutButton = new SwitchShortcutButton() + .OText("视角自控","Self-control"); +kqzlShortcutButton = new SwitchShortcutButton() + .OText("空气阻力","Airfriction"); + tkShortcutButton = new SwitchShortcutButton() + .OText("核心踏空","Fly"); + tytkShortcutButton = new SwitchShortcutButton() + .OText("腾跃踏空","Airjump"); + zlxgShortcutButton = new SwitchShortcutButton() + .OText("重力调节","Gravity"); + + xxShortcutButton = new SwitchShortcutButton() + .OText("[纵]Y+","Y++"); + xxxShortcutButton = new SwitchShortcutButton() + .OText("[纵]Y-","Y--"); + yyShortcutButton = new SwitchShortcutButton() + .OText("[横]X+","X++"); + yyyShortcutButton = new SwitchShortcutButton() + .OText("[横]X-","X--"); + zzShortcutButton = new SwitchShortcutButton() + .setText("Z++"); + zzzShortcutButton = new SwitchShortcutButton() + .setText("Z--"); + yjShortcutButton = new SwitchShortcutButton() + .OText("坐标控制","TP"); + gdShortcutButton = new SwitchShortcutButton() + .OText("冻结高度","freeze"); + djzzShortcutButton = new SwitchShortcutButton() + .OText("锁定坐标","lock"); + + } + + private SwitchContent shortcutSwitchContent; +Notification notification = Notification.getInstance(); + +private AsyncTask asyncTask; + + private AsyncTask asyncTask1; + private AsyncTask asyncTask2; + + private Thread thread1; + private Thread thread2; + private volatile boolean isRunning = true; // 添加一个标志变量,用于控制循环是否继续执行 + private ExecutorService executorService; + private Thread task1Thread = null; + private Thread task2Thread = null; + private Thread task3Thread = null; + private Thread task4Thread = null; + private Thread task5Thread = null; + private Thread task6Thread = null; + + + + /* ====== 控制线程 ====== */ + private volatile Thread flyThread = null; + private volatile boolean running = false; + + /* ====== 自控速度 ====== */ + private float flySpeed; // 默认速度 + + + private SwitchContentCard createsjSwitchContentCard() { + final SwitchContentCard reachSwitchContentCard = new SwitchContentCard("阻力修改", "改变游戏中对于玩家的综合阻力").OText("阻力修改","改变游戏中对于玩家的综合阻力","Modifyresistan","Modify and set resistance").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + reachSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + Text distanceTitleText = new Text() + .setText("数值: ","Value:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("9.55") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(10, 0, 9) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText.setText(String.format(""+newProgress)); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x380868) + 0x400) + 0x55A;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format("%.2f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x380868) + 0x400) + 0x55A;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + gjShortcutButton.show(); + } else { + gjShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(reachSwitchContentCard, gjShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + +ModuleManager.getInstance().setModuleEnabled("阻力修改|Modifyresistan", true); + // 创建线程并启动 + + + + } else { + ModuleManager.getInstance().setModuleEnabled("阻力修改|Modifyresistan", false); + distanceText.setText("9.55"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x380868) + 0x400) + 0x55A;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9.5", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return reachSwitchContentCard; + } + + + +private SwitchContentCard createxzSwitchContentCard() { + final SwitchContentCard xzSwitchContentCard = new SwitchContentCard("车体旋转", "车体快速自转").OText("车体旋转","车体快速自转","Rotate","Rapid rotation").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + xzSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + xzShortcutButton.show(); + } else { + xzShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(xzSwitchContentCard, xzShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { +Main.音效(); + if (newState) { +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xE4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("969.37", daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setFreezeDelayMs(20); +ModuleManager.getInstance().setModuleEnabled("车体旋转|Rotate", true); + + + } else { +ModuleManager.getInstance().setModuleEnabled("车体旋转|Rotate", false); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0xE4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("969.37", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setFreezeDelayMs(20); + } + return true; + } + }); + + return xzSwitchContentCard; + } + + + +private SwitchContentCard createhzlSwitchContentCard() { + final SwitchContentCard hzlSwitchContentCard = new SwitchContentCard("后坐力", "修改并设置武器的后坐力").OText("后坐力","修改并设置武器的后坐力","Recoil","Change and set the recoil of the weapon").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + hzlSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("反向: ","Reverse direction:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("-3.5") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(10, -10, -3) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + if (newProgress<0) { + distanceTitleText.setText("反向:","Reverse direction:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + AlguiMemTool.setFreezeDelayMs(0); + } + + + + if (newProgress ==0) { + distanceTitleText.setText("暂不支持","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + } + + if (newProgress>0) { + distanceTitleText.setText("正向:","Positive Direction:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + + + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + + + AlguiMemTool.setFreezeDelayMs(0); + } + if (newProgress!=0) { + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + AlguiMemTool.setFreezeDelayMs(0); + } + +} + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + AlguiMemTool.setFreezeDelayMs(0); + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + hzlShortcutButton.show(); + } else { + hzlShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(hzlSwitchContentCard, hzlShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + +ModuleManager.getInstance().setModuleEnabled("后坐力|Recoil", true); + + + + } else { + + ModuleManager.getInstance().setModuleEnabled("后坐力|Recoil", false); + distanceText.setText("无"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x70) + 0x10) + 0x10C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + AlguiMemTool.setFreezeDelayMs(0); + } + return true; + } + }); + + return hzlSwitchContentCard; + } + + + + + + + + +private SwitchContentCard createsjzkSwitchContentCard() { + final SwitchContentCard sjzkSwitchContentCard = new SwitchContentCard("视角自控", "向视角朝向飞行") + .OText("视角自控","向视角朝向飞行","Self-controlled flight","Towards the perspective towards flight"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + sjzkSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能") + .OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + sjzkShortcutButton.show(); + } else { + sjzkShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + + SyncUtil.sync(sjzkSwitchContentCard, sjzkShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + notification.make("视角自控", "已开启", "Self-controlled flight", "Open", Notification.Type.SUCCESS); + ModuleManager.getInstance().setModuleEnabled("视角自控|Self-controlled flight", true); + +ace.executeHiddenBinary("libalguivv.so"); + + } else { + notification.make("视角自控", "已关闭", "Self-controlled flight", "Close", Notification.Type.ERROR); + ModuleManager.getInstance().setModuleEnabled("视角自控|Self-controlled flight", false); + +ace.stopBinary("libalguivv.so"); + } + return true; + } + }); + + return sjzkSwitchContentCard; +} + + + + private SwitchContentCard createzzSwitchContentCard() { + + final SwitchContentCard yjSwitchContentCard = new SwitchContentCard("坐标控制", "根据不同的需求进行坐标级平移").OText("坐标控制台","根据不同的数值进行坐标轴平移","Coordinates","Coordinate Control Console").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + yjSwitchContentCard.setExpandableContent(column); + + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("X轴 [地图上横向]:","X:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(10000, -10000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr2, AlguiMemTool.TYPE_FLOAT, false, true); + AlguiMemTool.setFreezeDelayMs(0); + + } + } + + }); + column.addView(slider); + + Row distanceRow1 = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow1); + + final Text distanceTitleText1 = new Text() + .setText("Y轴 [地图上纵向]:","Y:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow1.addView(distanceTitleText1); + + final Text distanceText1 = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow1.addView(distanceText1); + + final Slider slider1 = new Slider(10000, -10000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText1.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText1.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + } + + }); + column.addView(slider1); + + Row distanceRow2 = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow2); + + final Text distanceTitleText2 = new Text() + .setText("Z轴 [人物高度]:","Z").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow2.addView(distanceTitleText2); + + final Text distanceText2 = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow2.addView(distanceText2); + + final Slider slider2 = new Slider(10000, -1000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText2.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText2.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + } + + }); + column.addView(slider2); + + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + + xxShortcutButton.show(); + xxxShortcutButton.show(); + yyShortcutButton.show(); + yyyShortcutButton.show(); + gdShortcutButton.show(); + djzzShortcutButton.show(); + zzShortcutButton.show(); + zzzShortcutButton.show(); + } else { + + xxShortcutButton.dismiss(); + xxxShortcutButton.dismiss(); + yyShortcutButton.dismiss(); + yyyShortcutButton.dismiss(); + gdShortcutButton.dismiss(); + djzzShortcutButton.dismiss(); + zzzShortcutButton.dismiss(); + zzShortcutButton.dismiss(); + stopTask2(); + stopTask1(); + stopTask3(); + stopTask4(); + gdShortcutButton.setChecked(false); + xxShortcutButton.setChecked(false); + xxxShortcutButton.setChecked(false); + yyShortcutButton.setChecked(false); + yyyShortcutButton.setChecked(false); + djzzShortcutButton.setChecked(false); + zzShortcutButton.setChecked(false); + zzzShortcutButton.setChecked(false); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(yjSwitchContentCard, yjShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); + slider1.setEnabled(newState); + slider1.setEnabled1(newState); + slider2.setEnabled(newState); + slider2.setEnabled1(newState); +Main.音效(); + if (newState) { +ModuleManager.getInstance().setModuleEnabled("坐标控制|Coordinates", true); + + + } else { +ModuleManager.getInstance().setModuleEnabled("坐标控制|Coordinates", false); + + } + return true; + } + }); + + xxShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked) { + if (isChecked) { + + startTask1(); + } else { + stopTask1(); + } + return true; // 允许状态切换 + } + }); + xxxShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked1) { + if (isChecked1) { + startTask3(); + + } else { + stopTask3(); + } + return true; // 允许状态切换 + } + }); + + yyShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked2) { + if (isChecked2) { + startTask2(); + + } else { + stopTask2(); + } + return true; // 允许状态切换 + } + }); + + yyyShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked3) { + if (isChecked3) { + startTask4(); + + } else { + stopTask4(); + } + return true; // 允许状态切换 + } + }); + + zzShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked4) { + if (isChecked4) { + startTask5(); + + } else { + stopTask5(); + } + return true; // 允许状态切换 + } + }); + + zzzShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked3) { + if (isChecked3) { + startTask6(); + + } else { + stopTask6(); + } + return true; // 允许状态切换 + } + }); + + gdShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked3) { + if (isChecked3) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue, daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + AlguiMemTool.setFreezeDelayMs(0); + } + return true; // 允许状态切换 + } + }); + + djzzShortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean isChecked3) { + if (isChecked3) { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue, daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + + String currentValue1 = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue1, daddr, AlguiMemTool.TYPE_FLOAT, true, true); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + + String currentValue2 = AlguiMemTool.getMemoryAddrData(daddr2, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue2, daddr2, AlguiMemTool.TYPE_FLOAT, true, true); + + + + } else { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + + String currentValue1 = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue1, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + + String currentValue2 = AlguiMemTool.getMemoryAddrData(daddr2, AlguiMemTool.TYPE_FLOAT); + AlguiMemTool.setMemoryAddrValue(""+currentValue2, daddr2, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + return true; // 允许状态切换 + } + }); + + return yjSwitchContentCard; + } + + private SwitchContentCard createtkSwitchContentCard() { + final SwitchContentCard tkSwitchContentCard = new SwitchContentCard("核心踏空", "使萌新核心可踏空行走").OText("核心踏空","使核心可以踏空行走","Fly","Make it possible to step on the air after disassembly"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + tkSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("数值: ","Value:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("1.0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(1024, 1, 512) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +// 设置包名 + + +// + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x288) + 0x0E8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x288) + 0x0E8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + tkShortcutButton.show(); + } else { + tkShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(tkSwitchContentCard, tkShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + +ModuleManager.getInstance().setModuleEnabled("核心踏空|Fly", true); + + } else { + + ModuleManager.getInstance().setModuleEnabled("核心踏空|Fly", false); + + distanceText.setText("1.0"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x288) + 0x0E8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("0.85", daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return tkSwitchContentCard; + } + +private SwitchContentCard createtytkSwitchContentCard() { + final SwitchContentCard tytkSwitchContentCard = new SwitchContentCard("腾跃踏空", "使有腾跃模块的铁臂可踏空行走").OText("腾跃踏空","装上腾跃即可踏空而行","AirJump","Fly for me."); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + tytkSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("数值: ","Value:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("5.0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(500, 2, 5) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + tytkShortcutButton.show(); + } else { + tytkShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(tytkSwitchContentCard, tytkShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + + +ModuleManager.getInstance().setModuleEnabled("腾越踏空|AirJump", true); + + } else { + +ModuleManager.getInstance().setModuleEnabled("腾越踏空|AirJump", false); + distanceText.setText("0.85"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("0.85", daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + return true; + } + }); + + return tytkSwitchContentCard; + } + + + + + + +private SwitchContentCard createhzkxSwitchContentCard() { + final SwitchContentCard hzkxSwitchContentCard = new SwitchContentCard("后坐力抗性", "减少后坐力对玩家的影响,但会导致行动会缓慢").OText("后坐力抗性","减少后坐力对玩家的影响,但会导致行动会缓慢","Resist","Reducing the impact of recoil on players"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + hzkxSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + hzkxShortcutButton.show(); + } else { + hzkxShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(hzkxSwitchContentCard, hzkxShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { +Main.音效(); + if (newState) { +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x456E28)+0x150)+0x40)+0x88)+0x70)+0xFC;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("17", daddr1, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x1A8)+0xFC;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("17", daddr21, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + +ModuleManager.getInstance().setModuleEnabled("后坐力抗性|Resist", true); + + } else { + +ModuleManager.getInstance().setModuleEnabled("后坐力抗性|Resist", false); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x456E28)+0x150)+0x40)+0x88)+0x70)+0xFC;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr1, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x1A8)+0xFC;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr21, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + return true; + } + }); + + return hzkxSwitchContentCard; + } + + + + + + + +private SwitchContentCard createwjfsSwitchContentCard() { + final SwitchContentCard wjfsSwitchContentCard = new SwitchContentCard("无迹飞梭", "毫无轨迹的后坐力移动方式").OText("无迹飞梭","毫无轨迹的后坐力移动方式","Spacebounce","Flight mode without trajectory"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + wjfsSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + wjfsShortcutButton.show(); + } else { + wjfsShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(wjfsSwitchContentCard, wjfsShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { +Main.音效(); + if (newState) { +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30)+0x10)+0x750)+0x78)+0x430)+0xC8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-869", daddr1, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x70)+0xC8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-869", daddr21, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + +ModuleManager.getInstance().setModuleEnabled("无迹飞梭|Spacebounce", true); + + + + } else { +ModuleManager.getInstance().setModuleEnabled("无迹飞梭|Spacebounce", true); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30)+0x10)+0x750)+0x78)+0x430)+0xC8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr1, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x70)+0xC8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr21, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + return true; + } + }); + + return wjfsSwitchContentCard; + } + + + + + private ButtonContentCard createSwitchContentCard() { + final ButtonContentCard zzbutton = new ButtonContentCard("一键自杀", "传送到深渊", false) + .OText("一键自杀", "传送到深渊", "One-Click Suicide", "Teleport to Abyss") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + + + zzbutton.setClickCallback(new ClickCallback() { + @Override + public void onClick() { + 自杀(); + } + }); + + + + return zzbutton; +} + + + + + + private SwitchContentCard createhwbdSwitchContentCard() { + final SwitchContentCard hwbdSwitchContentCard = new SwitchContentCard("恒稳不倒", "玩家保持垂直于地面的稳定姿态,不会倒下").OText("恒稳不倒","玩家保持垂直于地面的稳定姿态,不会倒下","Nofall","Won't fall."); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + hwbdSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + hwbdShortcutButton.show(); + } else { + hwbdShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(hwbdSwitchContentCard, hwbdShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("恒稳不倒", "已开启","Nofall","Open", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("恒稳不倒|Nofall", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x4602C0) + 0xC0) + 0x60) + + 0x10) + 0x1A8) + 0xAC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x0;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x8;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr3, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool + .jump64(AlguiMemTool.jump64(AlguiMemTool + .jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(sAddr21 + 0xD274F8) + 0x168) + 0x340) + + 0x80) + 0xA0) + + 0x98;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("恒稳不倒", "已关闭","Nofall","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("恒稳不倒|Nofall", false); + + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x4602C0) + 0xC0) + 0x60) + + 0x10) + 0x1A8) + 0xAC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x0;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0xDCBC30) + 0x390) + 0xC0) + + 0x88) + 0x38) + 0x8;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr3, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool + .jump64(AlguiMemTool.jump64(AlguiMemTool + .jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(sAddr21 + 0xD274F8) + 0x168) + 0x340) + + 0x80) + 0xA0) + + 0x98;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } + return true; + } + }); + + return hwbdSwitchContentCard; + } + + + +private SwitchContentCard createjxmcSwitchContentCard() { + final SwitchContentCard jxmcSwitchContentCard = new SwitchContentCard("减小摩擦", "减小与地面的摩擦力").OText("减少摩擦","减小与地面的摩擦力","Friction","Reduce friction with the ground"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + jxmcSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + jxmcShortcutButton.show(); + } else { + jxmcShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(jxmcSwitchContentCard, jxmcShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("减小摩擦", "已开启","Friction","Open", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("减小摩擦|Friction", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + + 0x88) + 0x15C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x380868) + 0x28) + 0x0) + + 0x88) + 0xA0) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x456E28) + 0x150) + 0x40) + + 0x88) + 0x40) + 0x15C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr3, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool + .jump64(AlguiMemTool.jump64(AlguiMemTool + .jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(sAddr21 + 0x39F028) + 0x3D0) + 0x138) + + 0x88) + 0x88) + + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("减小摩擦", "已关闭","Friction","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("减小摩擦|Friction", false); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + + 0x88) + 0x15C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0x380868) + 0x28) + 0x0) + + 0x88) + 0xA0) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr2, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x456E28) + 0x150) + 0x40) + + 0x88) + 0x40) + 0x15C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr3, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool + .jump64(AlguiMemTool.jump64(AlguiMemTool + .jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(sAddr21 + 0x39F028) + 0x3D0) + 0x138) + + 0x88) + 0x88) + + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } + return true; + } + }); + + return jxmcSwitchContentCard; + } + + +private SwitchContentCard createjjxtSwitchContentCard() { + final SwitchContentCard jjxtSwitchContentCard = new SwitchContentCard("紧急固定", "紧急固定车体坐标").OText("紧急固定","紧急固定车体的坐标","Emergencyfixation","Emergency fixed coordinate"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + jjxtSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + jjxtShortcutButton.show(); + } else { + jjxtShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(jjxtSwitchContentCard, jjxtShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + + if (newState) { + notification.make("紧急固定", "已开启","Emergencyfixation","Open", Notification.Type.SUCCESS); + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + + 0xA0) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9399.08521", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + +ModuleManager.getInstance().setModuleEnabled("紧急固定|Emergencyfixation", true); + } else { + ModuleManager.getInstance().setModuleEnabled("紧急固定|Emergencyfixation", false); + notification.make("紧急固定", "已关闭","Emergencyfixation","Close", Notification.Type.ERROR); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + + 0xA0) + 0x164;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + return true; + } + }); + + return jjxtSwitchContentCard; + } + + private SwitchContentCard createkqzlSwitchContentCard() { + final SwitchContentCard kqzlSwitchContentCard = new SwitchContentCard("空气阻力", "增加空气阻力").OText("空气阻力","增加空气阻力","Airfriction","Increase the resistance of the air"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + kqzlSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + kqzlShortcutButton.show(); + } else { + kqzlShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(kqzlSwitchContentCard, kqzlShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("空气阻力", "已开启","Airfriction","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("空气阻力|Airfriction", true); + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCA3520)+0x50)+0x300)+0x1E8)+0x10)+0xF8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30)+0x388)+0x0)+0x88)+0x38)+0x68;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("3", daddr1, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + + + } else { +notification.make("空气阻力", "已关闭","Airfriction","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("空气阻力|Airfriction", false); + + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xCA3520)+0x50)+0x300)+0x1E8)+0x10)+0xF8;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30)+0x388)+0x0)+0x88)+0x38)+0x68;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1", daddr1, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return kqzlSwitchContentCard; + } + + +private SwitchContentCard createzlxgSwitchContentCard() { + final SwitchContentCard zlxgSwitchContentCard = new SwitchContentCard("重力调节", "修改人物重力").OText("重力调节","修改人物重力","Gravity","Change one's own gravity"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + zlxgSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("数值: ","Value:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(3, -3, 0) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcbc30)+0x3f8)+0x420)+0x28)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xdcbc30)+0x358)+0x440)+0x10)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr1, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcbc30)+0x3f8)+0x420)+0x28)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xdcbc30)+0x358)+0x440)+0x10)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + } + + }); + column.addView(slider); + + + + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + zlxgShortcutButton.show(); + } else { + zlxgShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(zlxgSwitchContentCard, zlxgShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + if (newState) { + + +ModuleManager.getInstance().setModuleEnabled("重力调节|Gravity", true); + + notification.make("重力调节", "已开启","Gravity","Open", Notification.Type.SUCCESS); + + + + } else { + +ModuleManager.getInstance().setModuleEnabled("重力调节|Gravity", false); + notification.make("重力调节", "已关闭","Gravity","Close", Notification.Type.ERROR); + distanceText.setText("0"); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xdcbc30)+0x3f8)+0x420)+0x28)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xdcbc30)+0x358)+0x440)+0x10)+0x80)+0xac;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr1, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return zlxgSwitchContentCard; + } + + + + +private SwitchContentCard createdlsjsSwitchContentCard() { + final SwitchContentCard dlsjsSwitchContentCard = new SwitchContentCard("推进加速","增加大力神速度").OText("推进加速","增加大力神速度","Propeller acceleration","Speed up the accelerator"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + dlsjsSwitchContentCard.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text() + .setText("数值: ","Value:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("5.0") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(500, 2, 5) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + + + + + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_DOUBLE, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功";; + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + new Hint() + .setMessage("Progress: " + progress) + .show(); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc69248)+0x328)+0x3c0)+0x180)+0x44;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + } + + }); + column.addView(slider); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + dlsjsShortcutButton.show(); + } else { + dlsjsShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(dlsjsSwitchContentCard, dlsjsShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + slider.setEnabled(newState); + slider.setEnabled1(newState); +Main.音效(); + + if (newState) { + notification.make("推进加速", "已开启","Propeller acceleration","Open", Notification.Type.SUCCESS); + + + +ModuleManager.getInstance().setModuleEnabled("推进加速|Propeller acceleration", true); + } else { + ModuleManager.getInstance().setModuleEnabled("推进加速|Propeller acceleration", false); + notification.make("推进加速", "已关闭","Propeller acceleration","Close", Notification.Type.ERROR); +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc69248)+0x328)+0x3c0)+0x180)+0x44;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0.85", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + } + return true; + } + }); + + return dlsjsSwitchContentCard; + } + + + + + + + + + + + + + + + + + + + + + + + + + + +private void 自杀() { + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( +AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDCBC30) + 0x380) + 0x1C0)+ 0x88) + 0x38) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-114000", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( +AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30) + 0x380) + 0x1C0)+ 0x88) + 0x38) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-114000", daddr1, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + +notification.make("一键自杀", "执行", Notification.Type.SUCCESS); + +} + + + + + + + + + + private void executeBehavior(String selectedOption, boolean enable) { + if (enable) { + ace.executeHiddenBinary(getAction(selectedOption)); // 添加行为到数组 + } else { + ace.executeHiddenBinary(getCloseAction(selectedOption)); + } + } + + private String getAction(String option) { + switch (option) { + + case"1": + + return "1"; + case"3": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC86780) + 0x330) + 0x118;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("9", daddr, AlguiMemTool.TYPE_DOUBLE, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + return "3"; + case"4": + return "4"; + + + default: + return "ONE"; + }} + private String getCloseAction(String option) { + switch (option) { + case "1": + return "1"; + case "option2": + return "行为2关闭"; + case "option3": + return "行为3关闭"; + default: + return "行为1关闭"; + }} + + + + + + + + + + + // 创建一个固定大小的线程池,这里使用 2 个线程 + + + private Runnable task1Logic = new Runnable() { + @Override + public void run() { + try { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + AlguiMemTool.setMemoryAddrValue("2000", daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue + 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + // 封装任务2的逻辑 + private Runnable task2Logic = new Runnable() { + @Override + public void run() { + try { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + AlguiMemTool.setMemoryAddrValue("2000", daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue + 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + private Runnable task3Logic = new Runnable() { + @Override + public void run() { + try { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA8; + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + AlguiMemTool.setMemoryAddrValue("2000", daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue - 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + private Runnable task4Logic = new Runnable() { + @Override + public void run() { + try { + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA0; + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + AlguiMemTool.setMemoryAddrValue("2000", daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue - 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + + private Runnable task5Logic = new Runnable() { + @Override + public void run() { + try { + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue + 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + private Runnable task6Logic = new Runnable() { + @Override + public void run() { + try { + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4; + + + + for (int i = 0; i < 10000; i++) { + if (Thread.currentThread().isInterrupted()) { + break; // 如果线程被中断,退出循环 + } + + String currentValue = AlguiMemTool.getMemoryAddrData(daddr1, AlguiMemTool.TYPE_FLOAT); + float currentFloatValue = Float.parseFloat(currentValue); + + float newValue = currentFloatValue - 100; + + AlguiMemTool.setMemoryAddrValue(String.valueOf(newValue), daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + Thread.sleep(50); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } + }; + + + + + // 启动任务1 + public void startTask1() { + if (task1Thread == null || !task1Thread.isAlive()) { + task1Thread = new Thread(task1Logic); + task1Thread.start(); + } + } + + // 启动任务2 + public void startTask2() { + if (task2Thread == null || !task2Thread.isAlive()) { + task2Thread = new Thread(task2Logic); + task2Thread.start(); + } + } + + public void startTask3() { + if (task3Thread == null || !task3Thread.isAlive()) { + task3Thread = new Thread(task3Logic); + task3Thread.start(); + } + } + + public void startTask4() { + if (task4Thread == null || !task4Thread.isAlive()) { + task4Thread = new Thread(task4Logic); + task4Thread.start(); + } + } + + public void startTask5() { + if (task5Thread == null || !task5Thread.isAlive()) { + task5Thread = new Thread(task5Logic); + task5Thread.start(); + } + } + + public void startTask6() { + if (task6Thread == null || !task6Thread.isAlive()) { + task6Thread = new Thread(task6Logic); + task6Thread.start(); + } + } + + // 停止任务1 + public void stopTask1() { + if (task1Thread != null && task1Thread.isAlive()) { + task1Thread.interrupt(); // 中断线程 + } + } + + // 停止任务2 + public void stopTask2() { + if (task2Thread != null && task2Thread.isAlive()) { + task2Thread.interrupt(); // 中断线程 + } + } + + public void stopTask3() { + if (task3Thread != null && task3Thread.isAlive()) { + task3Thread.interrupt(); // 中断线程 + } + } + + public void stopTask4() { + if (task4Thread != null && task4Thread.isAlive()) { + task4Thread.interrupt(); // 中断线程 + } + } + + + public void stopTask5() { + if (task5Thread != null && task5Thread.isAlive()) { + task5Thread.interrupt(); // 中断线程 + } + } + + public void stopTask6() { + if (task6Thread != null && task6Thread.isAlive()) { + task6Thread.interrupt(); // 中断线程 + } + } + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/RemoteLinkWatcher.java b/app/src/main/java/com/bytecat/algui/ui/category/RemoteLinkWatcher.java new file mode 100644 index 0000000..6966e7f --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/RemoteLinkWatcher.java @@ -0,0 +1,373 @@ +package com.bytecat.algui.ui.category; + +import android.content.Context; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.AlguiViews.AlguiV; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.ace; +import android.content.res.AssetFileDescriptor; +import android.media.MediaPlayer; +import com.bytecat.algui.ui.MIX; +import android.os.*; + +public class RemoteLinkWatcher { + + private static final String TAG = "RemoteLinkWatcher"; + private static MediaPlayer sMediaPlayer; // 整个类共用 + private static boolean sO泡Playing = false; // 防止重复播 +private static boolean lingbai = false; + private static boolean longtu = false; + private static boolean sub0Switch = false; + private static boolean subOn = false; + private static boolean nosubOn; + private static boolean nomasterSelfSwitch; + private static boolean allowSub = false; + private static boolean masterSelfSwitch = false; // 主控自己的远控开关 + private static String nama = ""; // 用于标识当前执行指令的控制者 +private static String lastMainCmd = ""; +private static String lastSubCmd = ""; +// 水印实时修改用 +private static boolean waterMarkEnable = false; // 开关 +private static String waterMarkContent; + + private static final Handler sMainHandler = + new Handler(Looper.getMainLooper()); + + public static void startWatching(final String sub0Url, final String subUrl, final Context context) { + new Thread(new Runnable() { + @Override + public void run() { + while (true) { + +if (Main.alreadyloggin) { + try { +// 主控检测 +String sub0Html = fetchContent(sub0Url); +sub0Switch = sub0Html.contains("!开!"); +allowSub = sub0Html.contains("&开&"); +masterSelfSwitch = sub0Html.contains("?开?"); +nomasterSelfSwitch = sub0Html.contains("?关?"); +String sub0Cmd = extractCommand(sub0Html); + + + + +// 主控 + if (nomasterSelfSwitch && lingbai) { + lingbai = false; + + sMainHandler.post(new Runnable() { + @Override + public void run() { + ModuleManager.getInstance().setModuleEnabled("远控者:凌白", false); + } + }); + + +} else if (sub0Switch && masterSelfSwitch && sub0Cmd != null) { + if (! lingbai) { + lastMainCmd = sub0Cmd; + Main.远控音效(); + ModuleManager.getInstance().setModuleEnabled("远控者:凌白", true, + makeSubtitlePrefix(sub0Cmd) + sub0Cmd); + lingbai = true; + } + // 每次轮询刷新副标题 + ModuleManager.getInstance().setModuleSubtitle( + "远控者:凌白", + makeSubtitlePrefix(sub0Cmd) + sub0Cmd); + handleCommand(sub0Cmd.trim(), context); +} +String subHtml = fetchContent(subUrl); +subOn = subHtml.contains("!开!"); +nosubOn = subHtml.contains("!关!"); +String subCmd = extractCommand(subHtml); + + + + + + + + +// 副控 + if ((nosubOn || !allowSub) && longtu) { + longtu = false; + + sMainHandler.post(new Runnable() { + @Override + public void run() { + ModuleManager.getInstance().setModuleEnabled("远控者:龙图", false); + } + }); + +} else if (sub0Switch && allowSub && subOn && subCmd != null) { + +if (! longtu) { +lastSubCmd = subCmd; + Main.远控音效(); + ModuleManager.getInstance().setModuleEnabled("远控者:龙图", true, + makeSubtitlePrefix(sub0Cmd) + subCmd); + longtu=true; +} +ModuleManager.getInstance().setModuleSubtitle( + "远控者:龙图", + makeSubtitlePrefix(subCmd) + subCmd); + handleCommand(subCmd.trim(), context); +} + + + Thread.sleep(5000); + } catch (Exception e) { + Log.e(TAG, "轮询失败: " + e.getMessage()); + } + +} + } + } + }).start(); + + + + } + + private static String fetchContent(String urlString) throws Exception { + HttpURLConnection conn = null; + BufferedReader reader = null; + try { + URL url = new URL(urlString); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setConnectTimeout(5000); + conn.setReadTimeout(5000); + + reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + return sb.toString(); + } finally { + if (reader != null) try { reader.close(); } catch (Exception ignored) {} + if (conn != null) try { conn.disconnect(); } catch (Exception ignored) {} + } + } + + private static String extractCommand(String html) { + if (html == null) return null; + + // 1. 清理富文本 + String cleaned = html.replaceAll("<[^>]+>", " ") + .replace("&", "&") + .replace("lu003c", "<").replace("lu003e", ">") + .replace("lu0022", "\"").replace("lu0027", "'") + .replace('0','0').replace('1','1') + .replace('2','2').replace('3','3') + .replace('4','4').replace('5','5') + .replace('6','6').replace('7','7') + .replace('8','8').replace('9','9') + .replaceAll("\\s+", " ") + .trim(); + + // 2. 先抓第一对 ++...++(含脏尾) + Pattern pattern = Pattern.compile("\\+\\+([^+]+)\\+\\+"); + Matcher matcher = pattern.matcher(cleaned); + if (!matcher.find()) return null; + + String raw = matcher.group(1).trim(); + + // 3. 再砍脏尾巴:遇到 ", 或 "} 就截断 + int cut1 = raw.indexOf("\","); + int cut2 = raw.indexOf("\"}"); + int cut = (cut1 == -1) ? cut2 : Math.min(cut1, cut2 == -1 ? Integer.MAX_VALUE : cut2); + if (cut != -1) { + raw = raw.substring(0, cut).trim(); + } + + return raw.isEmpty() ? null : raw; +} + + + +private static boolean handleCommand(String cmd, Context context) { +if ("自杀".equals(cmd)) { +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( +AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDCBC30) + 0x380) + 0x1C0)+ 0x88) + 0x38) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-114000", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( +AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30) + 0x380) + 0x1C0)+ 0x88) + 0x38) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-114000", daddr1, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +return true; +} else if ("关闭范围".equals(cmd)) { +ace.stopBinary("libdfw.so");ace.stopBinary("libzcfw.so");ace.stopBinary("libxfw.so"); +return true; +} else if ("30帧率".equals(cmd)) { +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0x600) + 0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 +// 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("30", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +return true; +} else if ("停止发包开".equals(cmd)) { +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xD3FB68)+0x350)+0x3D0)+0x3C0)+0x160)+0x1F4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9", daddr,AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +return true; +} else if ("停止发包关".equals(cmd)) { +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xD3FB68)+0x350)+0x3D0)+0x3C0)+0x160)+0x1F4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0.00111516414", daddr,AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +return true; +} else if ("O泡开".equals(cmd)) { + synchronized (RemoteLinkWatcher.class) { + if (!sO泡Playing) { // 第一次才播 + try { + AssetFileDescriptor afd = MIX.getContext() + .getAssets() + .openFd("op.ogg"); + sMediaPlayer = new MediaPlayer(); + sMediaPlayer.setDataSource( + afd.getFileDescriptor(), + afd.getStartOffset(), + afd.getLength()); + sMediaPlayer.setLooping(true); + sMediaPlayer.prepare(); + sMediaPlayer.start(); + sO泡Playing = true; // 标记已播 + } catch (Exception e) { + Log.e(TAG, "O泡开失败", e); + } + } + } +return true; +} else if ("O泡关".equals(cmd)) { + synchronized (RemoteLinkWatcher.class) { + if (sMediaPlayer != null) { + if (sMediaPlayer.isPlaying()) { + sMediaPlayer.stop(); + } + sMediaPlayer.release(); + sMediaPlayer = null; + } + sO泡Playing = false; // 复位 + } + +return true; +} else if ("车体旋转开".equals(cmd)) { // 原逻辑... + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x70)+0xE4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-599", daddr1, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xCAF7F0)+0x500)+0x1E8)+0x100)+0x88)+0x54;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-599", daddr21, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(20);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +return true; +} else if ("车体旋转关".equals(cmd)) { // 原逻辑... + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCF0C0)+0x608)+0x0)+0x88)+0x70)+0xE4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr1, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xCAF7F0)+0x500)+0x1E8)+0x100)+0x88)+0x54;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr21, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +return true; +} else if ("万物偏移开".equals(cmd)) { // 原逻辑... + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_BSS);// 设置内存 +AlguiMemTool.MemorySearch("1", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("0.65211695", AlguiMemTool.TYPE_FLOAT, 0,false,true);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +return true; +} else if ("万物偏移关".equals(cmd)) { // 原逻辑... + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_BSS);// 设置内存 +AlguiMemTool.MemorySearch("0.65211695", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("1", AlguiMemTool.TYPE_FLOAT, 0,false,true);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +return true; +} else if ("无序挥击开".equals(cmd)) { // 原逻辑... +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x7C0)+ 0x7B0) + 0x608) + 0x7E4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9999", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +return true; +} else if ("无序挥击关".equals(cmd)) { // 原逻辑... +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss",AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x461420) + 0x6D8) + 0x7C0)+ 0x7B0) + 0x608) + 0x7E4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-185", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +return true; + } else { +// 未知指令则未命中 +return false; // 未命中 + } +} + +/** + * 通过 handleCommand 是否能匹配来判断指令是否有效 + */ +private static String makeSubtitlePrefix(String cmd) { + if (cmd == null || cmd.isEmpty()) return "说:"; + boolean hit = handleCommand(cmd, null); // 只探测,不真执行 + return hit ? "执行:" : "说:"; +} + + + // 获取当前执行者标识的 getter 方法 + public static String getNama() { + return nama; + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/SOULCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/SOULCategoryBox.java new file mode 100644 index 0000000..f6868e6 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/SOULCategoryBox.java @@ -0,0 +1,485 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.graphics.Typeface; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.effect.Hint; +import java.security.Identity; +import com.bytecat.algui.ace; +import android.content.Context; +import android.app.Activity; +import java.lang.ref.WeakReference; +import irene.window.algui.Tools.HackerTool; +import irene.window.algui.MainActivity; +import java.util.concurrent.ConcurrentHashMap; +import java.io.InputStream; +import java.io.File; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import irene.window.algui.AlGuiBubbleNotification; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.bytecat.algui.ui.component.Button; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.callback.ClickCallback; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.ArrayList; +import android.os.Handler; +import com.bytecat.algui.AlguiWindows.AlguiWinInform; +import com.bytecat.algui.AlguiManager.AlguiLog; +import com.bytecat.algui.AlguiViews.AlguiViewText; +import android.graphics.Paint; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import android.graphics.Canvas; +import android.view.SurfaceHolder; +import android.os.Looper; +import java.util.List; +import java.util.Map; +import java.util.Collections; +import android.view.WindowManager; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import android.graphics.Path; +import java.util.concurrent.TimeUnit; +import com.bytecat.algui.AlguiWindows.AlguiWinDraw; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.component.BoxContentCard; +import java.util.concurrent.CopyOnWriteArrayList; +import android.os.AsyncTask; +import com.bytecat.algui.effect.ArrayListView; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.effect.ColorPickerPopup; +import java.io.FileInputStream; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.BufferedWriter; +import android.graphics.PointF; +import java.util.Timer; +import java.util.TimerTask; +import com.bytecat.algui.ui.button.ShortcutButton; +import android.view.View; + + + + + + + + + + +public class SOULCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + + public SOULCategoryBox() { + createShortcutButtons(); + contentContainer + +.addView(createoneSwitchContentCard()) +.addView(createlhcqSwitchContentCard()) +.addView(createqjjsSwitchContentCard()) +.addView(createtwoSwitchContentCard()) + +; + } + + +private ShortcutButton oneShortcutButton; +private SwitchShortcutButton lhcqShortcutButton; +private SwitchShortcutButton qjjsShortcutButton; +private ShortcutButton twoShortcutButton; + + + + + +private void createShortcutButtons() { +oneShortcutButton = new ShortcutButton().setText("上天隐藏").OText("上天隐藏","Space").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +lhcqShortcutButton = new SwitchShortcutButton().setText("灵魂出窍").OText("灵魂出窍","Soul").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +qjjsShortcutButton = new SwitchShortcutButton().setText("全局加速").OText("全局加速","Velocity").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +twoShortcutButton = new ShortcutButton().setText("地面").OText("返回地面","Ground").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + + +} + + + + + + +private ButtonContentCard createoneSwitchContentCard() { + final ButtonContentCard zzbutton = new ButtonContentCard("上天隐藏", "休!的一声,飞到了极高空", false) + .OText("上天隐藏", "休!的一声飞到极高空", "Space Travel", "Transmitted to space") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + zzbutton.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + oneShortcutButton.show(); + } else { + oneShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + zzbutton.setClickCallback(new ClickCallback() { + @Override + public void onClick() { +//极高空 +notification.make("上天隐藏", "已执行","Space Travel","Open", Notification.Type.SUCCESS); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("999999", daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + +AlguiMemTool.setFreezeDelayMs(0); + + } + }); + +oneShortcutButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { +//极高空 +notification.make("上天隐藏", "已执行","Space Travel","Open", Notification.Type.SUCCESS); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x100) + 0x154;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("999999", daddr, AlguiMemTool.TYPE_FLOAT, true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setFreezeDelayMs(0); + } + }); + + return zzbutton; +} + + + +private SwitchContentCard createlhcqSwitchContentCard() { + final SwitchContentCard lhcqSwitchContentCard = new SwitchContentCard("灵魂出窍", "使灵体脱离真身").OText("灵魂出窍", "使灵体脱离真身","Soul out of body","To detach the soul from the true body").setChecked(false); + +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + lhcqSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + lhcqShortcutButton.show(); + } else { + lhcqShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(lhcqSwitchContentCard, lhcqShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + notification.make("灵魂出窍", "已开启","Soul","Open", Notification.Type.SUCCESS); +ModuleManager.getInstance().setModuleEnabled("灵魂出窍|Soul", true,"贝利亚"); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long jaddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB) + 0x453CBC; //从模块基址偏移获取目标地址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + AlguiMemTool.setMemoryAddrValue("200", jaddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 + +//灵体开 + + + + } else { + notification.make("灵魂出窍", "已关闭","Soul","close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("灵魂出窍|Soul", false); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long jaddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB) + 0x453CBC; //从模块基址偏移获取目标地址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + AlguiMemTool.setMemoryAddrValue("30", jaddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 + +//灵体关 + + + } + return true; + } + }); + return lhcqSwitchContentCard; +} + + +private SwitchContentCard createqjjsSwitchContentCard() { + final SwitchContentCard qjjsSwitchContentCard = new SwitchContentCard("全局加速", "增加灵魂出窍稳定性").OText("全局加速", "增加灵魂出窍稳定性","Velocity","Enhance stability").setChecked(false); + +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + qjjsSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + qjjsShortcutButton.show(); + } else { + qjjsShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(qjjsSwitchContentCard, qjjsShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +//如果还没开就正常执行,否则不执行 +if (!WorldCategoryBox.qjjs) { + +//这里写全局加速开启代码 + ModuleManager.getInstance().setModuleEnabled("全局加速|Velocity", true); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x960) + 0x18) + 0x210) + 0x208;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("-9999999", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; +//改变变量 + +notification.make("全局加速", "已开启","Velocity","Open", Notification.Type.SUCCESS); +//改变变量 +WorldCategoryBox.qjjs=true; +}else{ +notification.make("全局加速", "您已在[世界]菜单中开启","Velocity","No No No", Notification.Type.ERROR); +} + + } else { + + //如果还没关就正常执行,否则不执行 +if (WorldCategoryBox.qjjs) { + ModuleManager.getInstance().setModuleEnabled("全局加速|Velocity", false); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x960) + 0x18) + 0x210) + 0x208;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("500", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; +//改变变量 + +//这里写全局加速关闭代码 + +notification.make("全局加速", "已关闭","Velocity","Close", Notification.Type.SUCCESS); +//改变变量 +WorldCategoryBox.qjjs=false; +}else{ +notification.make("全局加速", "您已在[世界]菜单中关闭","Velocity","No No No", Notification.Type.ERROR); +} + + } + return true; + } + }); + + + + return qjjsSwitchContentCard; +} + + +private ButtonContentCard createtwoSwitchContentCard() { + final ButtonContentCard zbutton = new ButtonContentCard("返回地面", "传送到地面", false) + .OText("返回地面", "传送到地面", "Return to the ground", "Transmit to the ground") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + +Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + zbutton.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + twoShortcutButton.show(); + } else { + twoShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + + + zbutton.setClickCallback(new ClickCallback() { + @Override + public void onClick() { + +//回地面 +notification.make("返回地面", "已执行","Return to the ground","Open", Notification.Type.SUCCESS); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("3000", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setMemoryAddrValue("3000", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + }); + +twoShortcutButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + +//回地面 +notification.make("返回地面", "已执行","Return to the ground","Open", Notification.Type.SUCCESS); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x454090) + 0x0) + 0x88) + 0x40) + 0xA4;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("3000", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + AlguiMemTool.setMemoryAddrValue("3000", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + } + }); + + return zbutton; +} + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/SettingCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/SettingCategoryBox.java new file mode 100644 index 0000000..c9cae03 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/SettingCategoryBox.java @@ -0,0 +1,255 @@ +package com.bytecat.algui.ui.category; + +import android.graphics.Color; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.component.RadioGroup; +import android.graphics.Typeface; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.ace; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.effect.Hint; +import java.io.File; +import com.bytecat.algui.effect.ColorPickerPopup; + +public class SettingCategoryBox extends CategoryBox { + + private Notification notification; + + // 添加一个静态变量来保存点击背景关闭功能的状态 + public static boolean enableClickBackgroundClose = true; + + + + //快捷键 + private SwitchShortcutButton ysjShortcutButton; + + + + + public SettingCategoryBox() { + notification = Notification.getInstance(); + initUI(); + createShortcutButtons(); + contentContainer + + .addView(createlaunSwitchContentCard()) + .addView(createSwitchContentCard()); + contentContainer.build().addView(picker) + ; + } + + + +private void createShortcutButtons() { +ysjShortcutButton = new SwitchShortcutButton() +.setText("功能列表").OText("功能列表","ArrayList"); + +} + + private void initUI() { + addSettingCards(); + } + + private void addSettingCards() { + // 点击背景关闭界面设置 + StatefulButton clickBgCloseButton = new StatefulButton("点击背景关闭界面","Close Shortcut", enableClickBackgroundClose); + clickBgCloseButton.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setMargins(BaseHelper.dip2pxInt(15), BaseHelper.dip2pxInt(5), BaseHelper.dip2pxInt(15), BaseHelper.dip2pxInt(5))); + clickBgCloseButton.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + enableClickBackgroundClose = newState; + if (newState) { + + notification.make("设置", "已开启", Notification.Type.SUCCESS); + } else { + + notification.make("设置", "已关闭", Notification.Type.ERROR); + } + return true; + } + }); + contentContainer.addView(clickBgCloseButton); + +} + + +private ButtonContentCard createlaunSwitchContentCard() { + final ButtonContentCard zzbutton = new ButtonContentCard("语言切换", "Language", false); + final String configDir = "/sdcard/Android/data/com.vortex.celestial/files/"; + final String filePath = configDir + "/switch.lang"; + zzbutton.OText("语言切换", "中/英文切换", "Language Switch", "Switch between Chinese and English") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + zzbutton.setClickCallback(new ClickCallback() { + @Override + public void onClick() { +File file = new File(filePath); +try { +// 确保目录存在 +File dir = new File(configDir); +if (!dir.exists()) { +dir.mkdirs(); +} + + +if (!file.exists()) {//如果没有 +file.createNewFile();//就创建(中文) +notification.make("已切换中文", "重启软件生效", Notification.Type.SUCCESS); +}else{//如果有 +file.delete();//就删除(英文) +notification.make("Already switched to English", "Restart the software to take effect", Notification.Type.SUCCESS); +} + + + + + +} catch (Exception e) { +e.printStackTrace(); +} + + + + } + }); + + + return zzbutton; +} + + + + + + + +private ButtonContentCard createSwitchContentCard() { + final ButtonContentCard zzbutton = new ButtonContentCard("切换音效", "切换使用功能时播放的音效").OText("切换音效","切换使用功能时播放的音效","effect","Switch sound effect").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + zzbutton.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + +final Text reachText = new Text() + .setText("切换:","Switch:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(reachText); + + final RadioGroup radioGroup = new RadioGroup(); + radioGroup.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(15))); // 底部外边距为15dp + radioGroup.setEnabled(true); // 启用单选按钮组 + radioGroup.addButton("音效1","one", "1"); // 添加第一个选项 + radioGroup.addButton("音效2","two", "2"); // 添加第三个选项 + radioGroup.addButton("音效3","three", "3"); // 添加第三个选项 + + final String[] selectedOption = {"1"}; // 默认选中第一个选项 + radioGroup.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); + column.addView(radioGroup); // 将单选按钮组添加到内容区域 + + + zzbutton.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + + executeBehavior1(selectedOption[0], true); // 执行选中的行为 + + + + } + }); + + + return zzbutton; +} + + + + + +ColorPickerPopup picker = new ColorPickerPopup(MIX.getContext()); + + + + +private void executeBehavior1(String selectedOption, boolean enable) { + if (enable) { +ace.executeHiddenBinary(getAction1(selectedOption)); + } else { + } + } + + + + + +private String getAction1(String option) {//音效 + switch (option) { + case "1": +Main.vt1=true; +Main.vt2=false; +Main.vt3=false; + return "音效1"; + + case "2": +Main.vt1=false; +Main.vt2=true; +Main.vt3=false; + return "音效2"; + + case "3": +Main.vt1=false; +Main.vt2=false; +Main.vt3=true; + return "音效3"; + + default: + return "音效1"; + } + + } + + // 可以添加更多设置卡片... + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/SettingCategoryBox.java.bak b/app/src/main/java/com/bytecat/algui/ui/category/SettingCategoryBox.java.bak new file mode 100644 index 0000000..0d35c0d --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/SettingCategoryBox.java.bak @@ -0,0 +1,255 @@ +package com.bytecat.algui.ui.category; + +import android.graphics.Color; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.StatefulButton; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.ui.component.RadioGroup; +import android.graphics.Typeface; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.ace; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.effect.Hint; +import java.io.File; +import com.bytecat.algui.effect.ColorPickerPopup; + +public class SettingCategoryBox extends CategoryBox { + + private Notification notification; + + // 添加一个静态变量来保存点击背景关闭功能的状态 + public static boolean enableClickBackgroundClose = true; + + + + //快捷键 + private SwitchShortcutButton ysjShortcutButton; + + + + + public SettingCategoryBox() { + notification = Notification.getInstance(); + initUI(); + createShortcutButtons(); + contentContainer + + .addView(createlaunSwitchContentCard()) + .addView(createSwitchContentCard()); + contentContainer.build().addView(picker) + ; + } + + + +private void createShortcutButtons() { +ysjShortcutButton = new SwitchShortcutButton() +.setText("功能列表").OText("功能列表","ArrayList"); + +} + + private void initUI() { + addSettingCards(); + } + + private void addSettingCards() { + // 点击背景关闭界面设置 + StatefulButton clickBgCloseButton = new StatefulButton("点击背景关闭界面","Close Shortcut", enableClickBackgroundClose); + clickBgCloseButton.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setMargins(BaseHelper.dip2pxInt(15), BaseHelper.dip2pxInt(5), BaseHelper.dip2pxInt(15), BaseHelper.dip2pxInt(5))); + clickBgCloseButton.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + enableClickBackgroundClose = newState; + if (newState) { + + notification.make("设置", "已开启", Notification.Type.SUCCESS); + } else { + + notification.make("设置", "已关闭", Notification.Type.ERROR); + } + return true; + } + }); + contentContainer.addView(clickBgCloseButton); + +} + + +private ButtonContentCard createlaunSwitchContentCard() { + final ButtonContentCard zzbutton = new ButtonContentCard("语言切换", "Language", false); + final String configDir = "/sdcard/TC配置文件/"; + final String filePath = configDir + "/switch.lang"; + zzbutton.OText("语言切换", "中/英文切换", "Language Switch", "Switch between Chinese and English") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + zzbutton.setClickCallback(new ClickCallback() { + @Override + public void onClick() { +File file = new File(filePath); +try { +// 确保目录存在 +File dir = new File(configDir); +if (!dir.exists()) { +dir.mkdirs(); +} + + +if (!file.exists()) {//如果没有 +file.createNewFile();//就创建(中文) +notification.make("已切换中文", "重启软件生效", Notification.Type.SUCCESS); +}else{//如果有 +file.delete();//就删除(英文) +notification.make("Already switched to English", "Restart the software to take effect", Notification.Type.SUCCESS); +} + + + + + +} catch (Exception e) { +e.printStackTrace(); +} + + + + } + }); + + + return zzbutton; +} + + + + + + + +private ButtonContentCard createSwitchContentCard() { + final ButtonContentCard zzbutton = new ButtonContentCard("切换音效", "切换使用功能时播放的音效").OText("切换音效","切换使用功能时播放的音效","effect","Switch sound effect").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10))); + zzbutton.setExpandableContent(column); + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + +final Text reachText = new Text() + .setText("切换:","Switch:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(reachText); + + final RadioGroup radioGroup = new RadioGroup(); + radioGroup.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(15))); // 底部外边距为15dp + radioGroup.setEnabled(true); // 启用单选按钮组 + radioGroup.addButton("音效1","one", "1"); // 添加第一个选项 + radioGroup.addButton("音效2","two", "2"); // 添加第三个选项 + radioGroup.addButton("音效3","three", "3"); // 添加第三个选项 + + final String[] selectedOption = {"1"}; // 默认选中第一个选项 + radioGroup.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); + column.addView(radioGroup); // 将单选按钮组添加到内容区域 + + + zzbutton.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + + executeBehavior1(selectedOption[0], true); // 执行选中的行为 + + + + } + }); + + + return zzbutton; +} + + + + + +ColorPickerPopup picker = new ColorPickerPopup(MIX.getContext()); + + + + +private void executeBehavior1(String selectedOption, boolean enable) { + if (enable) { +ace.executeHiddenBinary(getAction1(selectedOption)); + } else { + } + } + + + + + +private String getAction1(String option) {//音效 + switch (option) { + case "1": +Main.vt1=true; +Main.vt2=false; +Main.vt3=false; + return "音效1"; + + case "2": +Main.vt1=false; +Main.vt2=true; +Main.vt3=false; + return "音效2"; + + case "3": +Main.vt1=false; +Main.vt2=false; +Main.vt3=true; + return "音效3"; + + default: + return "音效1"; + } + + } + + // 可以添加更多设置卡片... + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/SpecialCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/SpecialCategoryBox.java new file mode 100644 index 0000000..5955ee3 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/SpecialCategoryBox.java @@ -0,0 +1,679 @@ +package com.bytecat.algui.ui.category; + +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import android.graphics.Typeface; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.callback.SliderCallback; +import android.annotation.SuppressLint; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.ace; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.effect.Notification; +import java.util.Locale; +import com.bytecat.algui.effect.ModuleManager; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileOutputStream; +import android.content.Context; +import com.bytecat.algui.AlguiViews.AlguiV; +import android.app.Activity; +import android.os.AsyncTask; +import android.os.Environment; +import android.widget.Toast; +import java.io.FileInputStream; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; +import android.content.Intent; + + +public class SpecialCategoryBox extends CategoryBox { +// 放在 SpecialCategoryBox.java 最顶部 + + + + + Notification notification = Notification.getInstance(); + +/** + * 把 ini 文件里第一个匹配 key 的行改成指定值 + * 文件固定:/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini + * 如文件不存在会自动创建 + */ + + + +private static final String INI_PATH = + "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini"; + + +public static void configWrite(String key, String newValue) { + final String path = "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini"; + File file = new File(path); + if (!file.getParentFile().exists()) file.getParentFile().mkdirs(); + + List lines = new ArrayList<>(); + BufferedReader br = null; + BufferedWriter bw = null; + boolean found = false; + + try { + // 1. 读 + if (file.exists()) { + br = new BufferedReader(new FileReader(file)); + String line; + while ((line = br.readLine()) != null) { + String trim = line.trim(); + if (trim.startsWith(key + " = ") || trim.startsWith(key + " = ")) { + lines.add(key + " = " + newValue); + found = true; + } else { + lines.add(line); + } + } + } + // 2. 如果没找到,追加一行 + if (!found) { + lines.add(key + " = " + newValue); + } + // 3. 写 + bw = new BufferedWriter(new FileWriter(file)); + for (String l : lines) { + bw.write(l); + bw.newLine(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { if (br != null) br.close(); } catch (IOException ignore) {} + try { if (bw != null) bw.close(); } catch (IOException ignore) {} + } +} + + + + + +/** + * 在 [graphic_setting] 节下 添加/删除 hdr = 1 + * 文件固定:/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini + * @param enable true=添加 false=删除 + */ +public static void configWriteHdr(boolean enable) { + final String path = "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini"; + final String sectionStart = "[graphic_setting]"; + final String targetLine = "hdr = 1"; + + File file = new File(path); + if (!file.getParentFile().exists()) file.getParentFile().mkdirs(); + + List lines = new ArrayList<>(); + BufferedReader br = null; + BufferedWriter bw = null; + boolean inSection = false; + boolean foundHdr = false; + + try { + if (file.exists()) { + br = new BufferedReader(new FileReader(file)); + String line; + while ((line = br.readLine()) != null) { + String trim = line.trim(); + + // 进入/离开 [graphic_setting] + if (trim.equals(sectionStart)) { + inSection = true; + lines.add(line); + continue; + } + if (trim.startsWith("[") && !trim.equals(sectionStart)) { + inSection = false; + } + + // 在目标节内处理 hdr + if (inSection && trim.equals(targetLine)) { + foundHdr = true; + if (!enable) continue; // 删除 + } + lines.add(line); + } + br.close(); + } + + // 如果文件不存在,先补节 + if (!lines.contains(sectionStart)) { + lines.add(sectionStart); + } + + // 需要添加且没找到 hdr + if (enable && !foundHdr) { + // 找出最后一行索引再插入 + int insertAt = lines.size(); + for (int i = 0; i < lines.size(); i++) { + if (lines.get(i).trim().equals(sectionStart)) { + insertAt = i + 1; + while (insertAt < lines.size() && !lines.get(insertAt).trim().startsWith("[")) { + insertAt++; + } + break; + } + } + lines.add(insertAt, targetLine); + } + + // 写回 + bw = new BufferedWriter(new FileWriter(file)); + for (String l : lines) bw.write(l + "\n"); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { if (br != null) br.close(); } catch (IOException ignore) {} + try { if (bw != null) bw.close(); } catch (IOException ignore) {} + } +} + + +//波动消除检测 +private boolean isSfxLevelZero() { + File f = new File(INI_PATH); + if (!f.exists()) return false; + + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(f)); + String line; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.startsWith("sfx_level=") || line.startsWith("sfx_level =")) { + String val = line.split("=")[1].trim(); + return "0".equals(val); + } + } + } catch (IOException ignore) { + } finally { + if (br != null) try { br.close(); } catch (IOException ignore) {} + } + return false; +} + +//hdr检测 +private boolean isHdrOn() { + final String path = "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini"; + final String sectionStart = "[graphic_setting]"; + final String targetLine = "hdr = 1"; + + File file = new File(path); + if (!file.exists()) return false; + + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(file)); + String line; + boolean inSection = false; + while ((line = br.readLine()) != null) { + String trim = line.trim(); + if (trim.equals(sectionStart)) { + inSection = true; + continue; + } + if (trim.startsWith("[") && !trim.equals(sectionStart)) { + inSection = false; + } + if (inSection && trim.equals(targetLine)) { + return true; + } + } + } catch (IOException ignore) { + } finally { + if (br != null) try { br.close(); } catch (IOException ignore) {} + } + return false; +} + +//阴影检测 +private boolean isShadowOn() { + File f = new File(INI_PATH); + if (!f.exists()) return false; + + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(f)); + String line; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.startsWith("shadow_quality=") || line.startsWith("shadow_quality =")) { + String val = line.split("=")[1].trim(); + return "1".equals(val); + } + } + } catch (IOException ignore) { + } finally { + if (br != null) try { br.close(); } catch (IOException ignore) {} + } + return false; +} + + public SpecialCategoryBox() { + contentContainer + .addView(createhzwdSwitchContentCard()) + .addView(createhdrSwitchContentCard()) + .addView(createyinSwitchContentCard()) + .addView(createskySwitchContentCard()) + .addView(createSwitchContentCard()) + + ; + } + + + +private SwitchContentCard createhzwdSwitchContentCard() { + boolean defaultOn = isSfxLevelZero(); // ← 读取 ini 决定默认状态 + SwitchContentCard card = new SwitchContentCard("波动消除", "消除部分模块使用引起的空气波动", defaultOn); + + // 中英双语切换(复用统一语言文件 /sdcard/Android/data/com.vortex.celestial/files/switch.lang) + card.OText("波动消除", "消除部分模块使用引起的空气波动", "Wobble Removal", "Fix screen wobble caused by the module"); + + card.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + +if (newState){ +configWrite("sfx_level", "0"); +}else{ +configWrite("sfx_level", "2"); +} + +notification.make("修改完成","请重启游戏","Modification completed", "Please restart the game", Notification.Type.SUCCESS); + return true; + } + }); + return card; +} + + +private SwitchContentCard createhdrSwitchContentCard() { + boolean defaultOn = isHdrOn(); // ← 读取 hdr 状态决定默认 + SwitchContentCard card = new SwitchContentCard("高清", "HDR 画质", defaultOn); + + card.OText("高清", "[开启后绘制偏框]HDR 画质", "HDR Switch", "Toggle HDR rendering"); + + card.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + configWriteHdr(newState); // 新增/删除 hdr = 1 + notification.make("修改完成","请重启游戏","Modification completed", "Please restart the game", Notification.Type.SUCCESS); + return true; + } + }); + return card; +} + +private SwitchContentCard createyinSwitchContentCard() { + boolean defaultOn = isShadowOn(); // ← 状态决定默认 + SwitchContentCard card = new SwitchContentCard("阴影", "任意画质下添加阴影", defaultOn); + + card.OText("阴影", "任意画质下添加阴影", "Shadow Switch", "Add shadows at any quality level"); + + card.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (newState){ +configWrite("shadow_quality", "1"); +}else{ +configWrite("shadow_quality", "2"); +} + + notification.make("修改完成","请重启游戏","Modification completed", "Please restart the game", Notification.Type.SUCCESS); + return true; + } + }); + return card; +} + + + +private SwitchContentCard createskySwitchContentCard() { + final String TARGET_DIR = "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/Documents/res"; + final String TARGET_FILE = TARGET_DIR + "/levelsets.npk"; + final String ASSET1 = "levelsets.npk"; + final String ASSET2 = "levelsets2.npk"; + final long SIZE1 = 18884L; // 118.84 MB + + boolean defaultOn = new File(TARGET_FILE).exists() && new File(TARGET_FILE).length() == SIZE1; + + SwitchContentCard card = new SwitchContentCard("天空盒修改", "一键替换天空盒资源", defaultOn); + card.OText("天空盒修改", "一键替换天空盒资源", "Skybox Switch", "Enable custom skybox"); + + card.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + + new AsyncTask() { + @Override + protected Exception doInBackground(Void... voids) { + File dir = new File(TARGET_DIR); + if (!dir.exists()) dir.mkdirs(); + File dst = new File(TARGET_FILE); + + try { + if (newState) { + copyAsset(ASSET1, dst); + } else { + if (dst.exists()) dst.delete(); + copyAsset(ASSET2, dst); + } + return null; + } catch (IOException e) { + return e; + } + } + + @Override + protected void onPostExecute(Exception e) { + + + if (e == null) { + notification.make("修改完成", "请重启游戏", + "Modification completed", "Please restart the game", + Notification.Type.SUCCESS); + } else { + notification.make("失败", e.getMessage(), + "Failed", e.getMessage(), + Notification.Type.ERROR); + } + } + }.execute(); + + return true; + } + + private void copyAsset(String assetName, File dst) throws IOException { + android.content.res.AssetManager am = MIX.getContext().getAssets(); + java.io.InputStream in = am.open(assetName); + java.io.OutputStream out = new java.io.FileOutputStream(dst); + byte[] buf = new byte[8192]; + int len; + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } + }); + + return card; +} + + + + +private ButtonContentCard createSwitchContentCard() { +final ButtonContentCard button03 = new ButtonContentCard("游客账号", "可以对游客账号数据进行操作").OText("游客账号", "可以对游客账号数据进行操作", "One-Click Suicide", "Teleport to Abyss"); +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) // 宽度填满父视图 +.setHeight(BaseHelper.WrapContent) // 高度自适应内容 +.setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +button03.setExpandableContent(column); // 将内容区域设置到卡片中 + +// 添加一键开启的文本提示 +final Text reachText1 = new Text() +.setText("选择:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText1); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup1 = new RadioGroup(); +radioGroup1.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup1.setEnabled(true); +radioGroup1.addButton("清除", "1"); // 添加单次选项 +radioGroup1.addButton("保存", "2"); // 添加循环选项 +radioGroup1.addButton("加载", "3"); // 添加循环选项 +final String[] selectedOption = {"1"}; // 默认选中第一个选项 +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { +@Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); +column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + + + + +button03.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + +executeBehavior1(selectedOption[0]); // 执行选中的行为 + } + }); + + return button03; +} + + + +private void executeBehavior1(String selectedOption) { +getAction1(selectedOption); + } +private String getAction1(String option) {//账号 +Main.音效(); +notification.make("功能", "已执行完毕", Notification.Type.SUCCESS); + switch (option) { + case "1": +clearSharedPrefs(MIX.getContext()); +File neteaseDir = new File(Environment.getExternalStorageDirectory(), "netease"); +deleteRecursive(neteaseDir); +// 立即结束当前进程 +restartApp(MIX.getContext()); + return ""; + case "2": +try { + exportAccountData(MIX.getContext()); // 在主线程外执行更好 +} catch (IOException e) { + e.printStackTrace(); +} + return ""; + case "3": + +try { + restoreAccountData(MIX.getContext()); +} catch (IOException e) { + Toast.makeText(MIX.getContext(), "失败", Toast.LENGTH_LONG).show(); +} +restartApp(MIX.getContext()); + return ""; + default: + return ""; + } + + } + +public static void deleteRecursive(File fileOrDirectory) { + if (fileOrDirectory.isDirectory()) { + File[] children = fileOrDirectory.listFiles(); + if (children != null) { + for (File child : children) { + deleteRecursive(child); + } + } + } + fileOrDirectory.delete(); +} +public static void clearSharedPrefs(Context context) { + File prefsDir = new File(context.getApplicationInfo().dataDir, "shared_prefs"); + if (!prefsDir.exists() || !prefsDir.isDirectory()) { + return; + } + + File[] files = prefsDir.listFiles(); + if (files == null) return; + + for (File f : files) { + // 只删 .xml 文件,防止误删 + if (f.getName().endsWith(".xml")) { + boolean ok = f.delete(); + } + } +} + +// ================== 导出 ================== +public static void exportAccountData(Context ctx) throws IOException { + File cacheDir = new File(ctx.getCacheDir(), "export"); + FileUtilT.deleteRecursive(cacheDir); + cacheDir.mkdirs(); + + // 1. 复制 shared_prefs → Base64("1") + String dir1 = android.util.Base64.encodeToString("1".getBytes(), android.util.Base64.NO_WRAP); + File prefsSrc = new File(ctx.getApplicationInfo().dataDir, "shared_prefs"); + File prefsDst = new File(cacheDir, dir1); + FileUtilT.copyDir(prefsSrc, prefsDst); + + // 2. 复制 /sdcard/netease → Base64("2") + String dir2 = android.util.Base64.encodeToString("2".getBytes(), android.util.Base64.NO_WRAP); + File neteaseSrc = new File(Environment.getExternalStorageDirectory(), "netease"); + File neteaseDst = new File(cacheDir, dir2); + FileUtilT.copyDir(neteaseSrc, neteaseDst); + + // 3. 打包:Base64("backup") + ".dat" + String zipName = android.util.Base64.encodeToString("backup".getBytes(), android.util.Base64.NO_WRAP) + ".dat"; + File outDir = new File(Environment.getExternalStorageDirectory(), "TC配置文件"); + outDir.mkdirs(); + File zipFile = new File(outDir, zipName); + ZipUtilT.zip(cacheDir, zipFile); +} + + + + +public final class FileUtil { + public void copyDir(File src, File dst) throws IOException { + if (src == null || !src.exists()) return; + dst.mkdirs(); + File[] list = src.listFiles(); + if (list == null) return; + for (File f : list) { + File target = new File(dst, f.getName()); + if (f.isDirectory()) { + copyDir(f, target); + } else { + try (FileInputStream in = new FileInputStream(f); + FileOutputStream out = new FileOutputStream(target)) { + byte[] buf = new byte[8192]; + int len; + while ((len = in.read(buf)) > 0) out.write(buf, 0, len); + } + } + } + } + + public void deleteRecursive(File f) { + if (f == null || !f.exists()) return; + if (f.isDirectory()) { + File[] children = f.listFiles(); + if (children != null) for (File c : children) deleteRecursive(c); + } + f.delete(); + } +} + + + +// ================== 导入 ================== +public static void restoreAccountData(Context ctx) throws IOException { + // 1. 拼出 Base64 文件名 + String zipName = android.util.Base64.encodeToString("backup".getBytes(), android.util.Base64.NO_WRAP) + ".dat"; + File zipFile = new File(Environment.getExternalStorageDirectory(), "TC配置文件/" + zipName); + + File tempDir = new File(ctx.getCacheDir(), "restore"); + FileUtilT.deleteRecursive(tempDir); + tempDir.mkdirs(); + + // 2. 解压 + ZipUtilT.unzip(zipFile, tempDir); + + // 3. 覆盖 shared_prefs:Base64("1") + String dir1 = android.util.Base64.encodeToString("1".getBytes(), android.util.Base64.NO_WRAP); + File prefsDst = new File(ctx.getApplicationInfo().dataDir, "shared_prefs"); + File prefsSrc = new File(tempDir, dir1); + FileUtilT.deleteRecursive(prefsDst); + FileUtilT.copyDir(prefsSrc, prefsDst); + + // 4. 覆盖 /sdcard/netease:Base64("2") + String dir2 = android.util.Base64.encodeToString("2".getBytes(), android.util.Base64.NO_WRAP); + File neteaseDst = new File(Environment.getExternalStorageDirectory(), "netease"); + File neteaseSrc = new File(tempDir, dir2); + FileUtilT.deleteRecursive(neteaseDst); + FileUtilT.copyDir(neteaseSrc, neteaseDst); + + + + +} +private void restartApp(Context ctx) { + Intent intent = ctx.getPackageManager() + .getLaunchIntentForPackage(ctx.getPackageName()); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + ((Activity) ctx).finish(); + ctx.startActivity(intent); + Runtime.getRuntime().exit(0); // 立即结束旧进程 +} + + + + + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/SpecialCategoryBox.java.bak b/app/src/main/java/com/bytecat/algui/ui/category/SpecialCategoryBox.java.bak new file mode 100644 index 0000000..11d11a1 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/SpecialCategoryBox.java.bak @@ -0,0 +1,679 @@ +package com.bytecat.algui.ui.category; + +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import android.graphics.Typeface; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.callback.SliderCallback; +import android.annotation.SuppressLint; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.ace; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.effect.Notification; +import java.util.Locale; +import com.bytecat.algui.effect.ModuleManager; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileOutputStream; +import android.content.Context; +import com.bytecat.algui.AlguiViews.AlguiV; +import android.app.Activity; +import android.os.AsyncTask; +import android.os.Environment; +import android.widget.Toast; +import java.io.FileInputStream; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; +import android.content.Intent; + + +public class SpecialCategoryBox extends CategoryBox { +// 放在 SpecialCategoryBox.java 最顶部 + + + + + Notification notification = Notification.getInstance(); + +/** + * 把 ini 文件里第一个匹配 key 的行改成指定值 + * 文件固定:/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini + * 如文件不存在会自动创建 + */ + + + +private static final String INI_PATH = + "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini"; + + +public static void configWrite(String key, String newValue) { + final String path = "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini"; + File file = new File(path); + if (!file.getParentFile().exists()) file.getParentFile().mkdirs(); + + List lines = new ArrayList<>(); + BufferedReader br = null; + BufferedWriter bw = null; + boolean found = false; + + try { + // 1. 读 + if (file.exists()) { + br = new BufferedReader(new FileReader(file)); + String line; + while ((line = br.readLine()) != null) { + String trim = line.trim(); + if (trim.startsWith(key + " = ") || trim.startsWith(key + " = ")) { + lines.add(key + " = " + newValue); + found = true; + } else { + lines.add(line); + } + } + } + // 2. 如果没找到,追加一行 + if (!found) { + lines.add(key + " = " + newValue); + } + // 3. 写 + bw = new BufferedWriter(new FileWriter(file)); + for (String l : lines) { + bw.write(l); + bw.newLine(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { if (br != null) br.close(); } catch (IOException ignore) {} + try { if (bw != null) bw.close(); } catch (IOException ignore) {} + } +} + + + + + +/** + * 在 [graphic_setting] 节下 添加/删除 hdr = 1 + * 文件固定:/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini + * @param enable true=添加 false=删除 + */ +public static void configWriteHdr(boolean enable) { + final String path = "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini"; + final String sectionStart = "[graphic_setting]"; + final String targetLine = "hdr = 1"; + + File file = new File(path); + if (!file.getParentFile().exists()) file.getParentFile().mkdirs(); + + List lines = new ArrayList<>(); + BufferedReader br = null; + BufferedWriter bw = null; + boolean inSection = false; + boolean foundHdr = false; + + try { + if (file.exists()) { + br = new BufferedReader(new FileReader(file)); + String line; + while ((line = br.readLine()) != null) { + String trim = line.trim(); + + // 进入/离开 [graphic_setting] + if (trim.equals(sectionStart)) { + inSection = true; + lines.add(line); + continue; + } + if (trim.startsWith("[") && !trim.equals(sectionStart)) { + inSection = false; + } + + // 在目标节内处理 hdr + if (inSection && trim.equals(targetLine)) { + foundHdr = true; + if (!enable) continue; // 删除 + } + lines.add(line); + } + br.close(); + } + + // 如果文件不存在,先补节 + if (!lines.contains(sectionStart)) { + lines.add(sectionStart); + } + + // 需要添加且没找到 hdr + if (enable && !foundHdr) { + // 找出最后一行索引再插入 + int insertAt = lines.size(); + for (int i = 0; i < lines.size(); i++) { + if (lines.get(i).trim().equals(sectionStart)) { + insertAt = i + 1; + while (insertAt < lines.size() && !lines.get(insertAt).trim().startsWith("[")) { + insertAt++; + } + break; + } + } + lines.add(insertAt, targetLine); + } + + // 写回 + bw = new BufferedWriter(new FileWriter(file)); + for (String l : lines) bw.write(l + "\n"); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { if (br != null) br.close(); } catch (IOException ignore) {} + try { if (bw != null) bw.close(); } catch (IOException ignore) {} + } +} + + +//波动消除检测 +private boolean isSfxLevelZero() { + File f = new File(INI_PATH); + if (!f.exists()) return false; + + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(f)); + String line; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.startsWith("sfx_level=") || line.startsWith("sfx_level =")) { + String val = line.split("=")[1].trim(); + return "0".equals(val); + } + } + } catch (IOException ignore) { + } finally { + if (br != null) try { br.close(); } catch (IOException ignore) {} + } + return false; +} + +//hdr检测 +private boolean isHdrOn() { + final String path = "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/config.ini"; + final String sectionStart = "[graphic_setting]"; + final String targetLine = "hdr = 1"; + + File file = new File(path); + if (!file.exists()) return false; + + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(file)); + String line; + boolean inSection = false; + while ((line = br.readLine()) != null) { + String trim = line.trim(); + if (trim.equals(sectionStart)) { + inSection = true; + continue; + } + if (trim.startsWith("[") && !trim.equals(sectionStart)) { + inSection = false; + } + if (inSection && trim.equals(targetLine)) { + return true; + } + } + } catch (IOException ignore) { + } finally { + if (br != null) try { br.close(); } catch (IOException ignore) {} + } + return false; +} + +//阴影检测 +private boolean isShadowOn() { + File f = new File(INI_PATH); + if (!f.exists()) return false; + + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(f)); + String line; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.startsWith("shadow_quality=") || line.startsWith("shadow_quality =")) { + String val = line.split("=")[1].trim(); + return "1".equals(val); + } + } + } catch (IOException ignore) { + } finally { + if (br != null) try { br.close(); } catch (IOException ignore) {} + } + return false; +} + + public SpecialCategoryBox() { + contentContainer + .addView(createhzwdSwitchContentCard()) + .addView(createhdrSwitchContentCard()) + .addView(createyinSwitchContentCard()) + .addView(createskySwitchContentCard()) + .addView(createSwitchContentCard()) + + ; + } + + + +private SwitchContentCard createhzwdSwitchContentCard() { + boolean defaultOn = isSfxLevelZero(); // ← 读取 ini 决定默认状态 + SwitchContentCard card = new SwitchContentCard("波动消除", "消除部分模块使用引起的空气波动", defaultOn); + + // 中英双语切换(复用统一语言文件 /sdcard/TC配置文件/switch.lang) + card.OText("波动消除", "消除部分模块使用引起的空气波动", "Wobble Removal", "Fix screen wobble caused by the module"); + + card.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + +if (newState){ +configWrite("sfx_level", "0"); +}else{ +configWrite("sfx_level", "2"); +} + +notification.make("修改完成","请重启游戏","Modification completed", "Please restart the game", Notification.Type.SUCCESS); + return true; + } + }); + return card; +} + + +private SwitchContentCard createhdrSwitchContentCard() { + boolean defaultOn = isHdrOn(); // ← 读取 hdr 状态决定默认 + SwitchContentCard card = new SwitchContentCard("高清", "HDR 画质", defaultOn); + + card.OText("高清", "[开启后绘制偏框]HDR 画质", "HDR Switch", "Toggle HDR rendering"); + + card.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + configWriteHdr(newState); // 新增/删除 hdr = 1 + notification.make("修改完成","请重启游戏","Modification completed", "Please restart the game", Notification.Type.SUCCESS); + return true; + } + }); + return card; +} + +private SwitchContentCard createyinSwitchContentCard() { + boolean defaultOn = isShadowOn(); // ← 状态决定默认 + SwitchContentCard card = new SwitchContentCard("阴影", "任意画质下添加阴影", defaultOn); + + card.OText("阴影", "任意画质下添加阴影", "Shadow Switch", "Add shadows at any quality level"); + + card.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + Main.音效(); + if (newState){ +configWrite("shadow_quality", "1"); +}else{ +configWrite("shadow_quality", "2"); +} + + notification.make("修改完成","请重启游戏","Modification completed", "Please restart the game", Notification.Type.SUCCESS); + return true; + } + }); + return card; +} + + + +private SwitchContentCard createskySwitchContentCard() { + final String TARGET_DIR = "/storage/emulated/0/Android/data/com.vortex.celestial/files/Netease/wxzc/Documents/res"; + final String TARGET_FILE = TARGET_DIR + "/levelsets.npk"; + final String ASSET1 = "levelsets.npk"; + final String ASSET2 = "levelsets2.npk"; + final long SIZE1 = 18884L; // 118.84 MB + + boolean defaultOn = new File(TARGET_FILE).exists() && new File(TARGET_FILE).length() == SIZE1; + + SwitchContentCard card = new SwitchContentCard("天空盒修改", "一键替换天空盒资源", defaultOn); + card.OText("天空盒修改", "一键替换天空盒资源", "Skybox Switch", "Enable custom skybox"); + + card.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(final boolean newState) { + Main.音效(); + + + new AsyncTask() { + @Override + protected Exception doInBackground(Void... voids) { + File dir = new File(TARGET_DIR); + if (!dir.exists()) dir.mkdirs(); + File dst = new File(TARGET_FILE); + + try { + if (newState) { + copyAsset(ASSET1, dst); + } else { + if (dst.exists()) dst.delete(); + copyAsset(ASSET2, dst); + } + return null; + } catch (IOException e) { + return e; + } + } + + @Override + protected void onPostExecute(Exception e) { + + + if (e == null) { + notification.make("修改完成", "请重启游戏", + "Modification completed", "Please restart the game", + Notification.Type.SUCCESS); + } else { + notification.make("失败", e.getMessage(), + "Failed", e.getMessage(), + Notification.Type.ERROR); + } + } + }.execute(); + + return true; + } + + private void copyAsset(String assetName, File dst) throws IOException { + android.content.res.AssetManager am = MIX.getContext().getAssets(); + java.io.InputStream in = am.open(assetName); + java.io.OutputStream out = new java.io.FileOutputStream(dst); + byte[] buf = new byte[8192]; + int len; + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } + }); + + return card; +} + + + + +private ButtonContentCard createSwitchContentCard() { +final ButtonContentCard button03 = new ButtonContentCard("游客账号", "可以对游客账号数据进行操作").OText("游客账号", "可以对游客账号数据进行操作", "One-Click Suicide", "Teleport to Abyss"); +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) // 宽度填满父视图 +.setHeight(BaseHelper.WrapContent) // 高度自适应内容 +.setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +button03.setExpandableContent(column); // 将内容区域设置到卡片中 + +// 添加一键开启的文本提示 +final Text reachText1 = new Text() +.setText("选择:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText1); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup1 = new RadioGroup(); +radioGroup1.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup1.setEnabled(true); +radioGroup1.addButton("清除", "1"); // 添加单次选项 +radioGroup1.addButton("保存", "2"); // 添加循环选项 +radioGroup1.addButton("加载", "3"); // 添加循环选项 +final String[] selectedOption = {"1"}; // 默认选中第一个选项 +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { +@Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); +column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + + + + +button03.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + +executeBehavior1(selectedOption[0]); // 执行选中的行为 + } + }); + + return button03; +} + + + +private void executeBehavior1(String selectedOption) { +getAction1(selectedOption); + } +private String getAction1(String option) {//账号 +Main.音效(); +notification.make("功能", "已执行完毕", Notification.Type.SUCCESS); + switch (option) { + case "1": +clearSharedPrefs(MIX.getContext()); +File neteaseDir = new File(Environment.getExternalStorageDirectory(), "netease"); +deleteRecursive(neteaseDir); +// 立即结束当前进程 +restartApp(MIX.getContext()); + return ""; + case "2": +try { + exportAccountData(MIX.getContext()); // 在主线程外执行更好 +} catch (IOException e) { + e.printStackTrace(); +} + return ""; + case "3": + +try { + restoreAccountData(MIX.getContext()); +} catch (IOException e) { + Toast.makeText(MIX.getContext(), "失败", Toast.LENGTH_LONG).show(); +} +restartApp(MIX.getContext()); + return ""; + default: + return ""; + } + + } + +public static void deleteRecursive(File fileOrDirectory) { + if (fileOrDirectory.isDirectory()) { + File[] children = fileOrDirectory.listFiles(); + if (children != null) { + for (File child : children) { + deleteRecursive(child); + } + } + } + fileOrDirectory.delete(); +} +public static void clearSharedPrefs(Context context) { + File prefsDir = new File(context.getApplicationInfo().dataDir, "shared_prefs"); + if (!prefsDir.exists() || !prefsDir.isDirectory()) { + return; + } + + File[] files = prefsDir.listFiles(); + if (files == null) return; + + for (File f : files) { + // 只删 .xml 文件,防止误删 + if (f.getName().endsWith(".xml")) { + boolean ok = f.delete(); + } + } +} + +// ================== 导出 ================== +public static void exportAccountData(Context ctx) throws IOException { + File cacheDir = new File(ctx.getCacheDir(), "export"); + FileUtilT.deleteRecursive(cacheDir); + cacheDir.mkdirs(); + + // 1. 复制 shared_prefs → Base64("1") + String dir1 = android.util.Base64.encodeToString("1".getBytes(), android.util.Base64.NO_WRAP); + File prefsSrc = new File(ctx.getApplicationInfo().dataDir, "shared_prefs"); + File prefsDst = new File(cacheDir, dir1); + FileUtilT.copyDir(prefsSrc, prefsDst); + + // 2. 复制 /sdcard/netease → Base64("2") + String dir2 = android.util.Base64.encodeToString("2".getBytes(), android.util.Base64.NO_WRAP); + File neteaseSrc = new File(Environment.getExternalStorageDirectory(), "netease"); + File neteaseDst = new File(cacheDir, dir2); + FileUtilT.copyDir(neteaseSrc, neteaseDst); + + // 3. 打包:Base64("backup") + ".dat" + String zipName = android.util.Base64.encodeToString("backup".getBytes(), android.util.Base64.NO_WRAP) + ".dat"; + File outDir = new File(Environment.getExternalStorageDirectory(), "TC配置文件"); + outDir.mkdirs(); + File zipFile = new File(outDir, zipName); + ZipUtilT.zip(cacheDir, zipFile); +} + + + + +public final class FileUtil { + public void copyDir(File src, File dst) throws IOException { + if (src == null || !src.exists()) return; + dst.mkdirs(); + File[] list = src.listFiles(); + if (list == null) return; + for (File f : list) { + File target = new File(dst, f.getName()); + if (f.isDirectory()) { + copyDir(f, target); + } else { + try (FileInputStream in = new FileInputStream(f); + FileOutputStream out = new FileOutputStream(target)) { + byte[] buf = new byte[8192]; + int len; + while ((len = in.read(buf)) > 0) out.write(buf, 0, len); + } + } + } + } + + public void deleteRecursive(File f) { + if (f == null || !f.exists()) return; + if (f.isDirectory()) { + File[] children = f.listFiles(); + if (children != null) for (File c : children) deleteRecursive(c); + } + f.delete(); + } +} + + + +// ================== 导入 ================== +public static void restoreAccountData(Context ctx) throws IOException { + // 1. 拼出 Base64 文件名 + String zipName = android.util.Base64.encodeToString("backup".getBytes(), android.util.Base64.NO_WRAP) + ".dat"; + File zipFile = new File(Environment.getExternalStorageDirectory(), "TC配置文件/" + zipName); + + File tempDir = new File(ctx.getCacheDir(), "restore"); + FileUtilT.deleteRecursive(tempDir); + tempDir.mkdirs(); + + // 2. 解压 + ZipUtilT.unzip(zipFile, tempDir); + + // 3. 覆盖 shared_prefs:Base64("1") + String dir1 = android.util.Base64.encodeToString("1".getBytes(), android.util.Base64.NO_WRAP); + File prefsDst = new File(ctx.getApplicationInfo().dataDir, "shared_prefs"); + File prefsSrc = new File(tempDir, dir1); + FileUtilT.deleteRecursive(prefsDst); + FileUtilT.copyDir(prefsSrc, prefsDst); + + // 4. 覆盖 /sdcard/netease:Base64("2") + String dir2 = android.util.Base64.encodeToString("2".getBytes(), android.util.Base64.NO_WRAP); + File neteaseDst = new File(Environment.getExternalStorageDirectory(), "netease"); + File neteaseSrc = new File(tempDir, dir2); + FileUtilT.deleteRecursive(neteaseDst); + FileUtilT.copyDir(neteaseSrc, neteaseDst); + + + + +} +private void restartApp(Context ctx) { + Intent intent = ctx.getPackageManager() + .getLaunchIntentForPackage(ctx.getPackageName()); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + ((Activity) ctx).finish(); + ctx.startActivity(intent); + Runtime.getRuntime().exit(0); // 立即结束旧进程 +} + + + + + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/TPCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/TPCategoryBox.java new file mode 100644 index 0000000..7fa5287 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/TPCategoryBox.java @@ -0,0 +1,1011 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.graphics.Typeface; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.ui.component.ButtonContentCard; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.effect.Hint; + +public class TPCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + + + + +private static long daddr1x; +private static long daddr1y; +private static long daddr1z; + +private static boolean dongjiecs=false; +private static boolean dongjiecs2=false; +private static boolean dongjiecs3=false; +private static boolean dongjiecs4=false; +private static boolean dongjiecs5=false; + + + + +//快捷键 + + +//卡片 + public TPCategoryBox() { +createShortcutButtons(); + contentContainer +.addView(createSwitchContentCard01()) +.addView(createSwitchContentCard02()) +.addView(createSwitchContentCard03()) +.addView(createSwitchContentCard04()) +.addView(createSwitchContentCard05()) + +; + } + +//快捷键文本 +private void createShortcutButtons() { + + } + + + + + + + +private void 初始化() { + +//x +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList(); // 清空之前的搜索结果 +long sAddr0x = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); // 获取模块基址 +daddr1x = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr0x + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA8; // 跳转指针 + +//y +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList(); // 清空之前的搜索结果 +long sAddr0y = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); // 获取模块基址 +daddr1y = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr0y + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA4; // 跳转指针 + + +//z +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList(); // 清空之前的搜索结果 +long sAddr0z = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); // 获取模块基址 +daddr1z = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr0z + 0x454090) + 0x0) + 0x70) + 0x10) + 0xA0; // 跳转指针 + + + + } + + + + + + + + + +//冻结 +private void executeBehavior2(String selectedOption1) { +getAction2(selectedOption1); + } +private void executeBehavior7(String selectedOption1) { +getAction7(selectedOption1); + } +private void executeBehavior8(String selectedOption1) { +getAction8(selectedOption1); + } +private void executeBehavior9(String selectedOption1) { +getAction9(selectedOption1); + } +private void executeBehavior10(String selectedOption1) { +getAction10(selectedOption1); + } + + + +//传送 +private void executeBehavior1(String selectedOption) { +getAction1(selectedOption); + } +private void executeBehavior3(String selectedOption) { +getAction3(selectedOption); + } +private void executeBehavior4(String selectedOption) { +getAction4(selectedOption); + } +private void executeBehavior5(String selectedOption) { +getAction5(selectedOption); + } +private void executeBehavior6(String selectedOption) { +getAction6(selectedOption); + } + + + +private String getAction2(String option) {//冻结传送 + switch (option) { + case "1": +dongjiecs=false; + return ""; + case "2": +dongjiecs=true; + return ""; + default: + return ""; + } + + } +private String getAction7(String option) {//冻结传送 + switch (option) { + case "1": +dongjiecs2=false; + return ""; + case "2": +dongjiecs2=true; + return ""; + default: + return ""; + } + + } +private String getAction8(String option) {//冻结传送 + switch (option) { + case "1": +dongjiecs3=false; + return ""; + case "2": +dongjiecs3=true; + return ""; + default: + return ""; + } + + } +private String getAction9(String option) {//冻结传送 + switch (option) { + case "1": +dongjiecs4=false; + return ""; + case "2": +dongjiecs4=true; + return ""; + default: + return ""; + } + + } +private String getAction10(String option) {//冻结传送 + switch (option) { + case "1": +dongjiecs5=false; + return ""; + case "2": +dongjiecs5=true; + return ""; + default: + return ""; + } + + } + + + + + + + + + + + + + + + +private String getAction1(String option) {//超级风暴 +Main.音效(); +notification.make("传送", "已执行完毕", Notification.Type.SUCCESS); +初始化(); + switch (option) { + case "1": +AlguiMemTool.setMemoryAddrValue("730", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true); +AlguiMemTool.setMemoryAddrValue("500", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true); +AlguiMemTool.setMemoryAddrValue("-3517", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs ,true); + return ""; + case "2": + AlguiMemTool.setMemoryAddrValue("1299", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-11745.0341796875", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("9276.235351", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + return ""; + case "3": +AlguiMemTool.setMemoryAddrValue("0", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-14571", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-4057", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + return ""; + case "4": + AlguiMemTool.setMemoryAddrValue("-200", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-2028", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("9627", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + + return ""; + case "5": + AlguiMemTool.setMemoryAddrValue("1600", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("9825", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("11275", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + + return ""; + case "6": + AlguiMemTool.setMemoryAddrValue("-429", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-11405.460", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-1871.13", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + + return ""; + case "7": + AlguiMemTool.setMemoryAddrValue("410", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-5424", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-13166", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + return ""; + case "8": + AlguiMemTool.setMemoryAddrValue("3600", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("7046.460", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-10906", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + + return ""; + case "9": + AlguiMemTool.setMemoryAddrValue("500", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-25.4606", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-11460", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + return ""; + case "10": + AlguiMemTool.setMemoryAddrValue("-500", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-9261.46063232531", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("5181.1367187", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + + return ""; + case "11": + AlguiMemTool.setMemoryAddrValue("516.3", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-4983.46", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-6715", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + return ""; + case "12": + + AlguiMemTool.setMemoryAddrValue("-228", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("11391.4", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("9863", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + + return ""; + case "13": + + + AlguiMemTool.setMemoryAddrValue("455", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-11707.4", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-10474", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + return ""; + case "14": + AlguiMemTool.setMemoryAddrValue("-53", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-1830", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-710", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + + return ""; + case "15": + + AlguiMemTool.setMemoryAddrValue("170", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-4938.4606323253187", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-2341.13671875", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + return ""; + case "16": + + AlguiMemTool.setMemoryAddrValue("-415", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-8118", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("5658", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + return ""; + case "17": + + AlguiMemTool.setMemoryAddrValue("932", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-11249", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("8823", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + return ""; + case "18": + AlguiMemTool.setMemoryAddrValue("710", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("9252", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + AlguiMemTool.setMemoryAddrValue("-1237", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs,true);//修改值 + + + + return ""; + default: + return ""; + } + + } + + +private String getAction3(String option) {//单人风暴 +Main.音效(); +notification.make("传送", "已执行完毕", Notification.Type.SUCCESS); +初始化(); + switch (option) { + case "1": + AlguiMemTool.setMemoryAddrValue("3031", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("999", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("-297", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + return ""; + case "2": + AlguiMemTool.setMemoryAddrValue("999", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("-5324", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("-1950", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + return ""; + case "3": + AlguiMemTool.setMemoryAddrValue("1594", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("-5739", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("2004", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + return ""; + case "4": + AlguiMemTool.setMemoryAddrValue("50", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("-5863", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("6712", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + + return ""; + case "5": + AlguiMemTool.setMemoryAddrValue("50", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("-6712", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + AlguiMemTool.setMemoryAddrValue("-5863", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs2,true); + + + return ""; + default: + return ""; + } + + } + +private String getAction4(String option) {//乱斗 +Main.音效(); +notification.make("传送", "已执行完毕", Notification.Type.SUCCESS); +初始化(); + switch (option) { + case "1": + AlguiMemTool.setMemoryAddrValue("799", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs3,true); + AlguiMemTool.setMemoryAddrValue("2932.19", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs3,true); + AlguiMemTool.setMemoryAddrValue("-4221", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs3,true); + return ""; + case "2": + AlguiMemTool.setMemoryAddrValue("1500", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs3,true); + AlguiMemTool.setMemoryAddrValue("-5937.94", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs3,true); + AlguiMemTool.setMemoryAddrValue("3917", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs3,true); + + return ""; + default: + return ""; + } + + } + +private String getAction5(String option) {//占点 +Main.音效(); +notification.make("传送", "已执行完毕", Notification.Type.SUCCESS); +初始化(); + switch (option) { + case "1": + AlguiMemTool.setMemoryAddrValue("300", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-51.941", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-2015", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + return ""; + case "2": + AlguiMemTool.setMemoryAddrValue("633", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-254", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-603", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + return ""; + case "3": + AlguiMemTool.setMemoryAddrValue("509", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("0.751619", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-3474", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + + return ""; + case "4": + AlguiMemTool.setMemoryAddrValue("300", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-1181.94", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-247", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + + + return ""; + case "5": + AlguiMemTool.setMemoryAddrValue("1394", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("218", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("3164", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + + + + return ""; + case "6": + AlguiMemTool.setMemoryAddrValue("470", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("77.41", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-1738", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + return ""; + case "7": + AlguiMemTool.setMemoryAddrValue("120", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("151.94", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-1193", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + + return ""; + case "8": + AlguiMemTool.setMemoryAddrValue("390", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-235.9", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("-2510", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + + + + return ""; + case "9": + AlguiMemTool.setMemoryAddrValue("1400", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("5651.46", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + AlguiMemTool.setMemoryAddrValue("204", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs4,true); + return ""; + default: + return ""; + } + + } + +private String getAction6(String option) {//擂台 +Main.音效(); +notification.make("传送", "已执行完毕", Notification.Type.SUCCESS); +初始化(); + switch (option) { + case "1": + AlguiMemTool.setMemoryAddrValue("803", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("-2245", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("272", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + return ""; + case "2": + AlguiMemTool.setMemoryAddrValue("803", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("1185", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("-1718", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + + return ""; + case "3": + AlguiMemTool.setMemoryAddrValue("803", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("1169", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("2253", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + return ""; + case "4": + AlguiMemTool.setMemoryAddrValue("-202", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("-1152", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("1185", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + + return ""; + case "5": + AlguiMemTool.setMemoryAddrValue("10", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("547", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("-616", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + + + return ""; + + case "6": + AlguiMemTool.setMemoryAddrValue("-90", daddr1y,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("1028", daddr1x,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + AlguiMemTool.setMemoryAddrValue("789", daddr1z,AlguiMemTool.TYPE_FLOAT, dongjiecs5,true); + + + return ""; + + default: + return ""; + } + + } + + + + +private ButtonContentCard createSwitchContentCard01() { +final ButtonContentCard button01 = new ButtonContentCard("超级风暴", "莱兮城"); +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) // 宽度填满父视图 +.setHeight(BaseHelper.WrapContent) // 高度自适应内容 +.setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +button01.setExpandableContent(column); // 将内容区域设置到卡片中 + +// 添加一键开启的文本提示 +final Text reachText1 = new Text() +.setText("选择地点:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText1); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup1 = new RadioGroup(); +radioGroup1.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup1.setEnabled(true); +radioGroup1.addButton("大业殿", "1"); // 添加单次选项 +radioGroup1.addButton("可汗石头", "2"); // 添加循环选项 +radioGroup1.addButton("玉皇宫", "3"); // 添加循环选项 +radioGroup1.addButton("菩提枫", "4"); // 添加单次选项 +radioGroup1.addButton("北岸高架", "5"); // 添加循环选项 +radioGroup1.addButton("长滩房子", "6"); // 添加循环选项 +radioGroup1.addButton("太平门", "7"); // 添加单次选项 +radioGroup1.addButton("大草原", "8"); // 添加循环选项 +radioGroup1.addButton("荷塘房子", "9"); // 添加循环选项 +radioGroup1.addButton("美食街车", "10"); // 添加单次选项 +radioGroup1.addButton("地龟山", "11"); // 添加循环选项 +radioGroup1.addButton("北岸木头", "12"); // 添加循环选项 +radioGroup1.addButton("可汗牙帐", "13"); // 添加单次选项 +radioGroup1.addButton("永昌地下", "14"); // 添加循环选项 +radioGroup1.addButton("永昌门", "15"); // 添加循环选项 +radioGroup1.addButton("食味街中", "16"); // 添加单次选项 +radioGroup1.addButton("玉皇宫房", "17"); // 添加循环选项 +radioGroup1.addButton("和顺门旁", "18"); // 添加循环选项 + +final String[] selectedOption = {"1"}; // 默认选中第一个选项 +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { +@Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); +column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + + +// 添加一键开启的文本提示 +final Text reachText2 = new Text() +.setText("冻结传送:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText2); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup2 = new RadioGroup(); +radioGroup2.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup2.setEnabled(true); +radioGroup2.addButton("关闭", "1"); // 添加单次选项 +radioGroup2.addButton("开启", "2"); // 添加循环选项 + +final String[] selectedOption1 = {"1"}; // 默认选中第一个选项 +radioGroup2.setRadioGroupCallback(new RadioGroupCallback() { +@Override +public void onChecked(String id) { +new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 +selectedOption1[0] = id; // 更新选中的选项 +executeBehavior2(selectedOption1[0]); // 执行选中的行为 +AlguiMemTool.setFreezeDelayMs(0); + } + }); +column.addView(radioGroup2); // 将单选按钮组添加到内容区域 + + +button01.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + +executeBehavior1(selectedOption[0]); // 执行选中的行为 + } + }); + + return button01; +} + + + + + + private ButtonContentCard createSwitchContentCard02() { +final ButtonContentCard button02 = new ButtonContentCard("单人风暴", "落尘之地"); +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) // 宽度填满父视图 +.setHeight(BaseHelper.WrapContent) // 高度自适应内容 +.setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +button02.setExpandableContent(column); // 将内容区域设置到卡片中 + +// 添加一键开启的文本提示 +final Text reachText1 = new Text() +.setText("选择地点:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText1); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup1 = new RadioGroup(); +radioGroup1.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup1.setEnabled(true); +radioGroup1.addButton("中心枢纽", "1"); // 添加单次选项 +radioGroup1.addButton("灰色工厂", "2"); // 添加循环选项 +radioGroup1.addButton("守望台", "3"); // 添加循环选项 +radioGroup1.addButton("零号仓库", "4"); // 添加单次选项 +radioGroup1.addButton("小试验场", "5"); // 添加循环选项 +final String[] selectedOption = {"1"}; // 默认选中第一个选项 +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { +@Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); +column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + + +// 添加一键开启的文本提示 +final Text reachText2 = new Text() +.setText("冻结传送:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText2); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup2 = new RadioGroup(); +radioGroup2.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup2.setEnabled(true); +radioGroup2.addButton("关闭", "1"); // 添加单次选项 +radioGroup2.addButton("开启", "2"); // 添加循环选项 + +final String[] selectedOption1 = {"1"}; // 默认选中第一个选项 +radioGroup2.setRadioGroupCallback(new RadioGroupCallback() { +@Override +public void onChecked(String id) { +new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 +selectedOption1[0] = id; // 更新选中的选项 +executeBehavior7(selectedOption1[0]); // 执行选中的行为 +AlguiMemTool.setFreezeDelayMs(0); + } + }); +column.addView(radioGroup2); // 将单选按钮组添加到内容区域 + + +button02.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + +executeBehavior3(selectedOption[0]); // 执行选中的行为 + } + }); + + return button02; +} + + +private ButtonContentCard createSwitchContentCard03() { +final ButtonContentCard button03 = new ButtonContentCard("乱斗模式", "马萨拉遗迹"); +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) // 宽度填满父视图 +.setHeight(BaseHelper.WrapContent) // 高度自适应内容 +.setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +button03.setExpandableContent(column); // 将内容区域设置到卡片中 + +// 添加一键开启的文本提示 +final Text reachText1 = new Text() +.setText("选择地点:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText1); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup1 = new RadioGroup(); +radioGroup1.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup1.setEnabled(true); +radioGroup1.addButton("空投点 1", "1"); // 添加单次选项 +radioGroup1.addButton("空投点 2", "2"); // 添加循环选项 +final String[] selectedOption = {"1"}; // 默认选中第一个选项 +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { +@Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); +column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + + +// 添加一键开启的文本提示 +final Text reachText2 = new Text() +.setText("冻结传送:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText2); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup2 = new RadioGroup(); +radioGroup2.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup2.setEnabled(true); +radioGroup2.addButton("关闭", "1"); // 添加单次选项 +radioGroup2.addButton("开启", "2"); // 添加循环选项 + +final String[] selectedOption1 = {"1"}; // 默认选中第一个选项 +radioGroup2.setRadioGroupCallback(new RadioGroupCallback() { +@Override +public void onChecked(String id) { +new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 +selectedOption1[0] = id; // 更新选中的选项 +executeBehavior8(selectedOption1[0]); // 执行选中的行为 +AlguiMemTool.setFreezeDelayMs(0); + } + }); +column.addView(radioGroup2); // 将单选按钮组添加到内容区域 + + +button03.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + +executeBehavior4(selectedOption[0]); // 执行选中的行为 + } + }); + + return button03; +} + + + + private ButtonContentCard createSwitchContentCard04() { +final ButtonContentCard button04 = new ButtonContentCard("占点模式", "远征|红石|禅院"); +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) // 宽度填满父视图 +.setHeight(BaseHelper.WrapContent) // 高度自适应内容 +.setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +button04.setExpandableContent(column); // 将内容区域设置到卡片中 + +// 添加一键开启的文本提示 +final Text reachText1 = new Text() +.setText("选择地点:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText1); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup1 = new RadioGroup(); +radioGroup1.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup1.setEnabled(true); +radioGroup1.addButton("远征进点", "1"); // 添加单次选项 +radioGroup1.addButton("远征高台1", "2"); // 添加循环选项 +radioGroup1.addButton("远征高台2", "3"); // 添加循环选项 +radioGroup1.addButton("红石进点", "4"); // 添加单次选项 +radioGroup1.addButton("红石高台1", "5"); // 添加循环选项 +radioGroup1.addButton("红石高台2", "6"); // 添加循环选项 +radioGroup1.addButton("禅院进点", "7"); // 添加循环选项 +radioGroup1.addButton("禅院高台1", "8"); // 添加单次选项 +radioGroup1.addButton("禅院高台2", "9"); // 添加循环选项 +final String[] selectedOption = {"1"}; // 默认选中第一个选项 +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { +@Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); +column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + + +// 添加一键开启的文本提示 +final Text reachText2 = new Text() +.setText("冻结传送:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText2); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup2 = new RadioGroup(); +radioGroup2.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup2.setEnabled(true); +radioGroup2.addButton("关闭", "1"); // 添加单次选项 +radioGroup2.addButton("开启", "2"); // 添加循环选项 + +final String[] selectedOption1 = {"1"}; // 默认选中第一个选项 +radioGroup2.setRadioGroupCallback(new RadioGroupCallback() { +@Override +public void onChecked(String id) { +new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 +selectedOption1[0] = id; // 更新选中的选项 +executeBehavior9(selectedOption1[0]); // 执行选中的行为 +AlguiMemTool.setFreezeDelayMs(0); + } + }); +column.addView(radioGroup2); // 将单选按钮组添加到内容区域 + + +button04.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + +executeBehavior5(selectedOption[0]); // 执行选中的行为 + } + }); + + return button04; +} + + + private ButtonContentCard createSwitchContentCard05() { +final ButtonContentCard button05 = new ButtonContentCard("无限擂台", ""); +// 创建一个可折叠的内容区域,用于放置设置选项 +Column column = new Column() +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) // 宽度填满父视图 +.setHeight(BaseHelper.WrapContent) // 高度自适应内容 +.setTopMargin(dip2pxInt(15))); // 顶部外边距为15dp +button05.setExpandableContent(column); // 将内容区域设置到卡片中 + +// 添加一键开启的文本提示 +final Text reachText1 = new Text() +.setText("选择地点:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText1); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup1 = new RadioGroup(); +radioGroup1.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup1.setEnabled(true); +radioGroup1.addButton("高台1", "1"); // 添加单次选项 +radioGroup1.addButton("高台2", "2"); // 添加循环选项 +radioGroup1.addButton("高台3", "3"); // 添加循环选项 +radioGroup1.addButton("地下空间", "4"); // 添加单次选项 +radioGroup1.addButton("中间柱子", "5"); // 添加循环选项 +radioGroup1.addButton("狭窄斜坡", "6"); // 添加循环选项 +final String[] selectedOption = {"1"}; // 默认选中第一个选项 +radioGroup1.setRadioGroupCallback(new RadioGroupCallback() { +@Override + public void onChecked(String id) { + new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 + selectedOption[0] = id; // 更新选中的选项 + } + }); +column.addView(radioGroup1); // 将单选按钮组添加到内容区域 + + + +// 添加一键开启的文本提示 +final Text reachText2 = new Text() +.setText("冻结传送:") +.setTextSize(10f) +.setTextColor(hexColor("#FFC5C5C5")) +.setTypeface(Typeface.DEFAULT_BOLD) +.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(5))); +column.addView(reachText2); // 将文本添加到内容区域 + +// 创建一个单选按钮组,用于选择一键开启的行为 +final RadioGroup radioGroup2 = new RadioGroup(); +radioGroup2.setLayoutParams(new LinearParams() +.setWidth(BaseHelper.MatchParent) +.setBottomMargin(dip2pxInt(15))); +radioGroup2.setEnabled(true); +radioGroup2.addButton("关闭", "1"); // 添加单次选项 +radioGroup2.addButton("开启", "2"); // 添加循环选项 + +final String[] selectedOption1 = {"1"}; // 默认选中第一个选项 +radioGroup2.setRadioGroupCallback(new RadioGroupCallback() { +@Override +public void onChecked(String id) { +new Hint().setMessage("Selected: " + id).show(); // 显示选中的选项 +selectedOption1[0] = id; // 更新选中的选项 +executeBehavior10(selectedOption1[0]); // 执行选中的行为 +AlguiMemTool.setFreezeDelayMs(0); + } + }); +column.addView(radioGroup2); // 将单选按钮组添加到内容区域 + + +button05.setClickCallback(new ClickCallback() {//这个是按钮 + @Override + public void onClick() { + +executeBehavior6(selectedOption[0]); // 执行选中的行为 + } + }); + + return button05; +} + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/WorldCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/WorldCategoryBox.java new file mode 100644 index 0000000..6b986c5 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/WorldCategoryBox.java @@ -0,0 +1,1202 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.graphics.Typeface; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.ui.button.kuai; +import android.widget.SeekBar; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.ace; +import java.util.Locale; + +public class WorldCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + +public static boolean qjjs = false; + +//快捷键 +private SwitchShortcutButton tbgdShortcutButton; +private SwitchShortcutButton tzfbShortcutButton; +private SwitchShortcutButton wwpyShortcutButton; +private SwitchShortcutButton ycjzShortcutButton; +private SwitchShortcutButton qjjsShortcutButton; +private SwitchShortcutButton zdcqShortcutButton; +private SwitchShortcutButton yichangShortcutButton; + +//卡片 + public WorldCategoryBox() { +createShortcutButtons(); + contentContainer + +.addView(createtbgdSwitchContentCard()) +.addView(createtzfbSwitchContentCard()) +.addView(createwwpySwitchContentCard()) +.addView(createycjzSwitchContentCard()) +.addView(createqjjsSwitchContentCard()) +.addView(createzdcqSwitchContentCard()) +.addView(createyichangSwitchContentCard()) +.addView(createskyboxSwitchContentCard()) + +; + } + +//快捷键文本 +private void createShortcutButtons() { + +tbgdShortcutButton = new SwitchShortcutButton().setText("铁臂固定").OText("铁臂固定","Nomove").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +tzfbShortcutButton = new SwitchShortcutButton().setText("停止发包").OText("停止发包","Contract").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +wwpyShortcutButton = new SwitchShortcutButton().setText("万物偏移").OText("万物偏移","Excursion").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +ycjzShortcutButton = new SwitchShortcutButton().setText("移除建筑").OText("移除建筑","Dismantling").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +qjjsShortcutButton = new SwitchShortcutButton().setText("全局加速").OText("全局加速","Velocity").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +zdcqShortcutButton = new SwitchShortcutButton().setText("子弹穿墙").OText("子弹穿墙","Penetrate").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); +yichangShortcutButton = new SwitchShortcutButton().setText("异常发包器").OText("异常发包器","Outsourcing").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + + + + + +} + + + + + + + + + + + + + + + + + + + + + + + private SwitchContentCard createtbgdSwitchContentCard() { + final SwitchContentCard tbgdSwitchContentCard = new SwitchContentCard("铁臂固定", "[仅自己可见]在玩家视角中固定全局铁臂位置").OText("铁臂固定","[仅自己可见]在玩家视角中固定全局铁臂位置","Nomove","Prohibit all players from moving in their own perspective.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10)) + ); + + + + tbgdSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + tbgdShortcutButton.show(); + } else { + tbgdShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(tbgdSwitchContentCard, tbgdShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("铁臂固定", "已开启","Nomove","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("铁臂固定|Nomove", true); + + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDD20F8) + 0xF8) + 0x800)+ 0x658) + 0x6B0) + 0x4FC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("8.47695338e-20", daddr,AlguiMemTool.TYPE_FLOAT, false,false);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("铁臂固定", "已关闭","Nomove","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("铁臂固定|Nomove", false); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDD20F8) + 0xF8) + 0x800)+ 0x658) + 0x6B0) + 0x4FC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("8.47695338e-21", daddr,AlguiMemTool.TYPE_FLOAT, false,false);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } + return true; + } + }); + + return tbgdSwitchContentCard; + } + + + private SwitchContentCard createtzfbSwitchContentCard() { + final SwitchContentCard tzfbSwitchContentCard = new SwitchContentCard("停止发包", "停止向服务器发送数据包").OText("停止发包","停止向服务器发送数据包","Contact","Stop the receiving and contracting of the server.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + tzfbSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + tzfbShortcutButton.show(); + } else { + tzfbShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(tzfbSwitchContentCard, tzfbShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("停止发包", "已开启","Contact","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("停止发包|Contact", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xD3FB68)+0x350)+0x3D0)+0x3C0)+0x160)+0x1F4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9", daddr,AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("停止发包", "已关闭","Contact","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("停止发包|Contact", false); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xD3FB68)+0x350)+0x3D0)+0x3C0)+0x160)+0x1F4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0.00111516414", daddr,AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + + } + return true; + } + }); + + return tzfbSwitchContentCard; + } + + + + private SwitchContentCard createwwpySwitchContentCard() { + final SwitchContentCard wwpySwitchContentCard = new SwitchContentCard("万物偏移", "[仅自己可见]使万物方向偏移且大小改变").OText("万物偏移","[仅自己可见]使万物方向偏移且大小改变","Excursion","Transform the world into a form from one's own perspective").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + wwpySwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + wwpyShortcutButton.show(); + } else { + wwpyShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(wwpySwitchContentCard, wwpyShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("万物偏移", "已开启","Excursion","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("万物偏移|Excursion", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_BSS);// 设置内存 +AlguiMemTool.MemorySearch("1", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("0.65211695", AlguiMemTool.TYPE_FLOAT, 0,false,true);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("万物偏移", "已关闭","Excursion","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("万物偏移|Excursion", false); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_BSS);// 设置内存 +AlguiMemTool.MemorySearch("0.65211695", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("1", AlguiMemTool.TYPE_FLOAT, 0,false,true);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return wwpySwitchContentCard; + } + + + + private SwitchContentCard createycjzSwitchContentCard() { + final SwitchContentCard ycjzSwitchContentCard = new SwitchContentCard("移除建筑", "移除所有建筑物,使玩家可穿过").OText("移除建筑","移除所有建筑物,您可穿过原来建筑物的位置","Dismantling","Remove all buildings.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + ycjzSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + ycjzShortcutButton.show(); + } else { + ycjzShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(ycjzSwitchContentCard, ycjzShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("移除建筑", "已开启","Dismantling","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("移除建筑|Dismantling", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_CODE_APP);// 设置内存 +AlguiMemTool.MemorySearch("4.3572124460608017E27", AlguiMemTool.TYPE_FLOAT);// 内存搜索// 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("-1", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("移除建筑", "已关闭","Dismantling","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("移除建筑|Dismantling", false); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_CODE_APP);// 设置内存 +AlguiMemTool.MemorySearch("4.3572124460608017E27", AlguiMemTool.TYPE_FLOAT);// 内存搜索// 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("14428.5986328125", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return ycjzSwitchContentCard; + } + + private SwitchContentCard createqjjsSwitchContentCard() { + final SwitchContentCard qjjsSwitchContentCard = new SwitchContentCard("全局加速", "[仅自己可见]加速烟雾消散、武器瞄准等").OText("全局加速","[仅自己可见]加速烟雾消散、武器瞄准等","Velocity","Accelerated special effects").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + qjjsSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + qjjsShortcutButton.show(); + } else { + qjjsShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(qjjsSwitchContentCard, qjjsShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + + Main.音效(); + + if (newState) { + +//如果还没开就正常执行,否则不执行 + if (!qjjs) { + +//这里写全局加速开启代码 + + notification.make("全局加速", "已开启","Velocity","Open", Notification.Type.SUCCESS); + ModuleManager.getInstance().setModuleEnabled("全局加速|Velocity", true); + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x960) + 0x18) + 0x210) + 0x208;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("-9999999", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; +//改变变量 + qjjs=true; + }else{ + notification.make("全局加速", "您已在[灵体]菜单中开启","Velocity","No No No", Notification.Type.ERROR); + } + + + } else { + + +//如果还没关就正常执行,否则不执行 + if (qjjs) { + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0x960) + 0x18) + 0x210) + 0x208;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("500", daddr, AlguiMemTool.TYPE_FLOAT, false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; +//改变变量 + +//这里写全局加速关闭代码 + + notification.make("全局加速", "已关闭","Velocity","Close", Notification.Type.SUCCESS); + ModuleManager.getInstance().setModuleEnabled("全局加速|Velocity", false); +//改变变量 + qjjs=false; + }else{ + notification.make("全局加速", "您已在[灵体]菜单中关闭","Velocity","No No No", Notification.Type.ERROR); + } + + + } + return true; + } + }); + + return qjjsSwitchContentCard; + } + + +private SwitchContentCard createzdcqSwitchContentCard() { + final SwitchContentCard zdcqSwitchContentCard = new SwitchContentCard("子弹穿墙", "使发射的子弹可以穿透部分墙体").OText("子弹穿墙","使发射的子弹可以穿透部分墙体","Penetrate","Bullets go through walls.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + zdcqSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + zdcqShortcutButton.show(); + } else { + zdcqShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(zdcqSwitchContentCard, zdcqShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("子弹穿墙", "已开启","Penetrate","Open" ,Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("子弹穿墙|Penetrate", true); +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0xDCB5E8);//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("子弹穿墙", "已关闭", "Penetrate","Close",Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("子弹穿墙|Penetrate", false); + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0xDCB5E8);//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("10", daddr, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return zdcqSwitchContentCard; + } + +private SwitchContentCard createyichangSwitchContentCard() { + // 创建快捷键按钮 + final SwitchShortcutButton yichangShortcutButton = new SwitchShortcutButton().setText("异常发包器").OText("异常发包器", "Outsourcing") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + final SwitchContentCard yichangSwitchContentCard = new SwitchContentCard("异常发包器", "向服务器发出自身的异常坐标") .OText("异常发包器", "向服务器发出自身的异常坐标", "Outsourcing", "Send abnormal coordinates of itself to the server") + .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + yichangSwitchContentCard.setExpandableContent(column); + + final Text reachText = new Text() + .setText("发包模式:","Outsourcing Mode:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(reachText); + + final RadioGroup radioGroup = new RadioGroup().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + radioGroup.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent)); + + radioGroup.setEnabled(true); // 启用单选按钮组 + radioGroup.addButton("断开连接","kick","1"); // 添加第一个选项 + radioGroup.addButton("全图起飞","Fly", "2"); // 添加第三个选项 + radioGroup.addButton("超级起飞","FlyPro", "5"); // 添加第三个选项 + radioGroup.addButton("传染数据","Share", "3"); // 添加第三个选项 + radioGroup.addButton("灰屏共鸣","Pestile", "7"); // 添加第三个选项 + radioGroup.addButton("数据同化","SharePro", "6"); // 添加第三个选项 + radioGroup.addButton("隐蔽模型","Stealth", "4"); // 添加第三个选项 + final String[] selectedOption = { "1" }; // 默认选中第一个选项 + radioGroup.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + + } + }); + column.addView(radioGroup); // 将单选按钮组添加到内容区域 + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + yichangShortcutButton.show(); + } else { + yichangShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(yichangSwitchContentCard, yichangShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + + Main.音效(); + if (newState) { + + executeBehavior1(selectedOption[0], true); // 执行选中的行为 + +ModuleManager.getInstance().setModuleEnabled("异常发包器|Outsourcing", true); + notification.make("异常发包器", "已开启","Outsourcing","Open", Notification.Type.SUCCESS); + } else { + notification.make("异常发包器", "已关闭","Outsourcing","Open", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("异常发包器|Outsourcing", false); + executeBehavior1(selectedOption[0], false); // 停止执行行为 + + } + return true; + } + }); + + return yichangSwitchContentCard; + } + + + + + + private SwitchContentCard createskyboxSwitchContentCard() { + + final SwitchContentCard skyboxSwitchContentCard = new SwitchContentCard("天空盒坐标", "对天空盒进行坐标级平移").OText("天空盒坐标", "对天空盒进行坐标级平移","Skybox coordinates","Modify skybox coordinates").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + skyboxSwitchContentCard.setExpandableContent(column); + + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text().setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setText("X轴:","X:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(10000, -10000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xc62e90)+0x0)+0x540; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xc62e90)+0x0)+0x540; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + } + } + + }); + column.addView(slider); + + Row distanceRow1 = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow1); + + final Text distanceTitleText1 = new Text() + .setText("Y轴:","Y:").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow1.addView(distanceTitleText1); + + final Text distanceText1 = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow1.addView(distanceText1); + + final Slider slider1 = new Slider(10000, -10000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText1.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc62e90)+0x0)+0x548; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText1.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x548; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + } + } + + }); + column.addView(slider1); + + Row distanceRow2 = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow2); + + final Text distanceTitleText2 = new Text() + .setText("Z轴:","Z").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow2.addView(distanceTitleText2); + + final Text distanceText2 = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow2.addView(distanceText2); + + final Slider slider2 = new Slider(10000, -1000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText2.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x544; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText2.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc62e90)+0x0)+0x544; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true, true); + +AlguiMemTool.setFreezeDelayMs(0); + } + } + + }); + column.addView(slider2); + + + +skyboxSwitchContentCard.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { +slider.setEnabled(newState); + slider.setEnabled1(newState); + slider1.setEnabled(newState); + slider1.setEnabled1(newState); + slider2.setEnabled(newState); + slider2.setEnabled1(newState); +Main.音效(); + if (newState) { +ModuleManager.getInstance().setModuleEnabled("天空盒坐标|Skybox coordinates", true); + + + } else { +ModuleManager.getInstance().setModuleEnabled("天空盒坐标|Skybox coordinates", false); + + +AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + + + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x540; + AlguiMemTool.setMemoryAddrValue("5", daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x544; + AlguiMemTool.setMemoryAddrValue("5", daddr2, AlguiMemTool.TYPE_FLOAT, false, true); + + long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x548; + AlguiMemTool.setMemoryAddrValue("5", daddr3, AlguiMemTool.TYPE_FLOAT, false, true); + + } + return true; + } + }); + + return skyboxSwitchContentCard; +} + + + + + + + + private void executeBehavior1(String selectedOption, boolean enable) { + if (enable) { + + ace.executeHiddenBinary(getAction1(selectedOption)); + + + } else { + + + ace.stopBinary(getCloseAction1(selectedOption)); + } + } + + + + + + private String getAction1(String option) {// 铁臂猎手 + switch (option) { + case "1": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x39E2E8) + 0x28) + 0x0) + + 0x70) + 0x68) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-25", daddr3, AlguiMemTool.TYPE_DWORD, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x380) + 0x1C0) + + 0x88) + 0x38) + 0xDC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-25", daddr2, AlguiMemTool.TYPE_DWORD, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + + + return "离线"; + + case "2": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr31 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr31 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr31 + 0x39E2E8) + 0x28) + 0x0) + + 0x70) + 0x68) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-41", daddr31, AlguiMemTool.TYPE_DWORD, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCBC30) + 0x380) + 0x1C0) + + 0x88) + 0x38) + 0xDC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-41", daddr21, AlguiMemTool.TYPE_DWORD, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + + + + return "起飞"; + case "3": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc69248)+0x328)+0x3c0)+0x180)+0x44;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("1.875", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + AlguiMemTool.setMemoryAddrValue("999", daddr, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + return "共享"; + + case "4": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long p1 = AlguiMemTool.jump64( AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30) + 0x390) + 0xC0) + 0x10 )+0x15C; + AlguiMemTool.setMemoryAddrValue("-114514", p1, AlguiMemTool.TYPE_DWORD,true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + long p2 = AlguiMemTool.jump64( AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30) + 0x390) + 0xC0) + 0x10 )+0x164; + AlguiMemTool.setMemoryAddrValue("-114514", p2, AlguiMemTool.TYPE_DWORD,true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + return "隐身"; + + case "5": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr1145 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr1145 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1145 + 0x454090) + 0x0) + 0x70) + 0x10) + 0x16C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("-1", daddr1145, AlguiMemTool.TYPE_DWORD,true,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + + AlguiMemTool.setFreezeDelayMs(0); + return "超飞"; + + case "6": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr12 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr12 = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr12 + 0xc69248)+0x328)+0x3c0)+0x180)+0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("1.875", daddr12, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + AlguiMemTool.setMemoryAddrValue("999", daddr12, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + + + return "超共享"; + case "7": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr13 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr13 = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr13 + 0xc69248)+0x328)+0x3c0)+0x180)+0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("1.875", daddr13, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + AlguiMemTool.setMemoryAddrValue("9999", daddr13, AlguiMemTool.TYPE_FLOAT, true,true);// 修改目标值 + + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + + AlguiMemTool.setFreezeDelayMs(0); + return "超享"; + + default: + return ""; + } + + } + +private String getCloseAction1(String option) { + + + + + + + + + + + switch (option) { + case "1": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + AlguiMemTool.setPackageName("com.vortex.celestial"); + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x39E2E8) + 0x28) + 0x0) + + 0x70) + 0x68) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("9", daddr3, AlguiMemTool.TYPE_DWORD, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + return "离线"; + case "2": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x380) + 0x1C0) + + 0x88) + 0x38) + 0xDC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("9", daddr2, AlguiMemTool.TYPE_DWORD, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + return "起飞"; + case "3": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc69248)+0x328)+0x3c0)+0x180)+0x44;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("1.875", daddr, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + return "起飞"; + case "4": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long p1 = AlguiMemTool.jump64( AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30) + 0x390) + 0xC0) + 0x10 )+0x15C; + AlguiMemTool.setMemoryAddrValue("-114514", p1, AlguiMemTool.TYPE_DWORD,false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + long p2 = AlguiMemTool.jump64( AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xDCBC30) + 0x390) + 0xC0) + 0x10 )+0x164; + AlguiMemTool.setMemoryAddrValue("-114514", p2, AlguiMemTool.TYPE_DWORD,false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + return "起飞"; + case "5": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + long sAddr1145 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr1145 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1145 + 0x454090) + 0x0) + 0x70) + 0x10) + 0x16C;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + + //跳转指针如果不直观请使用下面这种方式 + /* + long p1 = AlguiMemTool.jump64(sAddr + 0x88B8); + long p2 = AlguiMemTool.jump64(p1 + 0xA0); + long p3 = AlguiMemTool.jump64(p2 + 0x118); + long addr = p3 + 0x18; + */ + AlguiMemTool.setMemoryAddrValue("0", daddr1145, AlguiMemTool.TYPE_DWORD,false,true);//修改目标值 【如果需要冻结将false改为true】 return "开启成功"; + + return "起飞"; + case "6": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr12 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr12 = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr12 + 0xc69248)+0x328)+0x3c0)+0x180)+0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("1.875", daddr12, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + AlguiMemTool.setMemoryAddrValue("1.875", daddr12, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + + AlguiMemTool.setFreezeDelayMs(0); + return "超共享"; + + case "7": + AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 + AlguiMemTool.clearResultList();// 清空之前的搜索结果 + long sAddr13 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + long daddr13 = AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr13 + 0xc69248)+0x328)+0x3c0)+0x180)+0x14;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + AlguiMemTool.setMemoryAddrValue("1.875", daddr13, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + AlguiMemTool.setMemoryAddrValue("1.875", daddr13, AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 + + // 【如果需要冻结将false改为true】 + AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + + AlguiMemTool.setFreezeDelayMs(0); + return "超共享"; + default: + return ""; + } + } + + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/WorldCategoryBox.java.bak b/app/src/main/java/com/bytecat/algui/ui/category/WorldCategoryBox.java.bak new file mode 100644 index 0000000..710d96b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/WorldCategoryBox.java.bak @@ -0,0 +1,1016 @@ +package com.bytecat.algui.ui.category; + +import android.annotation.SuppressLint; +import android.graphics.Typeface; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SliderCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.Slider; +import com.bytecat.algui.ui.component.SwitchContentCard; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.util.SyncUtil; +import com.bytecat.algui.ui.Main; +import com.bytecat.algui.ui.MIX; +import com.bytecat.algui.AlguiHacker.AlguiMemTool; +import com.bytecat.algui.effect.Notification; +import com.bytecat.algui.ui.button.kuai; +import android.widget.SeekBar; +import com.bytecat.algui.effect.Hint; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.effect.ModuleManager; +import com.bytecat.algui.ui.component.RadioGroup; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.ace; +import java.util.Locale; + +public class WorldCategoryBox extends CategoryBox { + + Notification notification = Notification.getInstance(); + + + +//快捷键 +private SwitchShortcutButton tbgdShortcutButton; +private SwitchShortcutButton tzfbShortcutButton; +private SwitchShortcutButton wwpyShortcutButton; +private SwitchShortcutButton ycjzShortcutButton; +private SwitchShortcutButton qjjsShortcutButton; +private SwitchShortcutButton zdcqShortcutButton; +private SwitchShortcutButton yichangShortcutButton; + +//卡片 + public WorldCategoryBox() { +createShortcutButtons(); + contentContainer + +.addView(createtbgdSwitchContentCard()) +.addView(createtzfbSwitchContentCard()) +.addView(createwwpySwitchContentCard()) +.addView(createycjzSwitchContentCard()) +.addView(createqjjsSwitchContentCard()) +.addView(createzdcqSwitchContentCard()) +.addView(createyichangSwitchContentCard()) +.addView(createskyboxSwitchContentCard()) + +; + } + +//快捷键文本 +private void createShortcutButtons() { + +tbgdShortcutButton = new SwitchShortcutButton().setText("铁臂固定").OText("铁臂固定","Nomove").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); +tzfbShortcutButton = new SwitchShortcutButton().setText("停止发包").OText("停止发包","Contract").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); +wwpyShortcutButton = new SwitchShortcutButton().setText("万物偏移").OText("万物偏移","Excursion").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); +ycjzShortcutButton = new SwitchShortcutButton().setText("移除建筑").OText("移除建筑","Dismantling").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); +qjjsShortcutButton = new SwitchShortcutButton().setText("全局加速").OText("全局加速","Velocity").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); +zdcqShortcutButton = new SwitchShortcutButton().setText("子弹穿墙").OText("子弹穿墙","Penetrate").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); +yichangShortcutButton = new SwitchShortcutButton().setText("异常发包器").OText("异常发包器","Outsourcing").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + + + + + + +} + + + + + + + + + + + + + + + + + + + + + + + private SwitchContentCard createtbgdSwitchContentCard() { + final SwitchContentCard tbgdSwitchContentCard = new SwitchContentCard("铁臂固定", "[仅自己可见]在玩家视角中固定全局铁臂位置").OText("铁臂固定","[仅自己可见]在玩家视角中固定全局铁臂位置","Nomove","Prohibit all players from moving in their own perspective.").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10)) + ); + + + + tbgdSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + tbgdShortcutButton.show(); + } else { + tbgdShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(tbgdSwitchContentCard, tbgdShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("铁臂固定", "已开启","Nomove","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("铁臂固定|Nomove", true); + + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDD20F8) + 0xF8) + 0x800)+ 0x658) + 0x6B0) + 0x4FC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("8.47695338e-20", daddr,AlguiMemTool.TYPE_FLOAT, false,false);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("铁臂固定", "已关闭","Nomove","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("铁臂固定|Nomove", false); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xDD20F8) + 0xF8) + 0x800)+ 0x658) + 0x6B0) + 0x4FC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("8.47695338e-21", daddr,AlguiMemTool.TYPE_FLOAT, false,false);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } + return true; + } + }); + + return tbgdSwitchContentCard; + } + + + private SwitchContentCard createtzfbSwitchContentCard() { + final SwitchContentCard tzfbSwitchContentCard = new SwitchContentCard("停止发包", "停止向服务器发送数据包").OText("停止发包","停止向服务器发送数据包","Contact","Stop the receiving and contracting of the server.").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + tzfbSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + tzfbShortcutButton.show(); + } else { + tzfbShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(tzfbSwitchContentCard, tzfbShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("停止发包", "已开启","Contact","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("停止发包|Contact", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xD3FB68)+0x350)+0x3D0)+0x3C0)+0x160)+0x1F4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9", daddr,AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("停止发包", "已关闭","Contact","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("停止发包|Contact", false); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", +AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB + // cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xD3FB68)+0x350)+0x3D0)+0x3C0)+0x160)+0x1F4;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0.00111516414", daddr,AlguiMemTool.TYPE_FLOAT, false,true);// 修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + + } + return true; + } + }); + + return tzfbSwitchContentCard; + } + + + + private SwitchContentCard createwwpySwitchContentCard() { + final SwitchContentCard wwpySwitchContentCard = new SwitchContentCard("万物偏移", "[仅自己可见]使万物方向偏移且大小改变").OText("万物偏移","[仅自己可见]使万物方向偏移且大小改变","Excursion","Transform the world into a form from one's own perspective").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + wwpySwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + + ); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + wwpyShortcutButton.show(); + } else { + wwpyShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(wwpySwitchContentCard, wwpyShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("万物偏移", "已开启","Excursion","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("万物偏移|Excursion", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_BSS);// 设置内存 +AlguiMemTool.MemorySearch("1", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("0.65211695", AlguiMemTool.TYPE_FLOAT, 0,false,true);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("万物偏移", "已关闭","Excursion","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("万物偏移|Excursion", false); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_C_BSS);// 设置内存 +AlguiMemTool.MemorySearch("0.65211695", AlguiMemTool.TYPE_FLOAT);// 内存搜索 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("1", AlguiMemTool.TYPE_FLOAT, 0,false,true);// 修改值结果偏移修改 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return wwpySwitchContentCard; + } + + + + private SwitchContentCard createycjzSwitchContentCard() { + final SwitchContentCard ycjzSwitchContentCard = new SwitchContentCard("移除建筑", "移除所有建筑物,使玩家可穿过").OText("移除建筑","移除所有建筑物,您可穿过原来建筑物的位置","Dismantling","Remove all buildings.").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + ycjzSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + ycjzShortcutButton.show(); + } else { + ycjzShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(ycjzSwitchContentCard, ycjzShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("移除建筑", "已开启","Dismantling","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("移除建筑|Dismantling", true); +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_CODE_APP);// 设置内存 +AlguiMemTool.MemorySearch("4.3572124460608017E27", AlguiMemTool.TYPE_FLOAT);// 内存搜索// 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("-1", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } else { +notification.make("移除建筑", "已关闭","Dismantling","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("移除建筑|Dismantling", false); + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +AlguiMemTool.setMemoryArea(AlguiMemTool.RANGE_CODE_APP);// 设置内存 +AlguiMemTool.MemorySearch("4.3572124460608017E27", AlguiMemTool.TYPE_FLOAT);// 内存搜索// 【主特征码】 +AlguiMemTool.MemoryOffsetWrite("14428.5986328125", AlguiMemTool.TYPE_FLOAT, 4, false,false);// 修改值结果偏移修改 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return ycjzSwitchContentCard; + } + +private SwitchContentCard createqjjsSwitchContentCard() { + final SwitchContentCard qjjsSwitchContentCard = new SwitchContentCard("全局加速", "[仅自己可见]加速烟雾消散、武器瞄准等").OText("全局加速","[仅自己可见]加速烟雾消散、武器瞄准等","Velocity","Accelerated special effects").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + qjjsSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + qjjsShortcutButton.show(); + } else { + qjjsShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(qjjsSwitchContentCard, qjjsShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("全局加速", "已开启","Velocity","Open", Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("全局加速|Velocity", true); +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xC898A0)+0x2B8)+0x2C8)+0x778)+0x2E8)+0x70;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("1999", daddr, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);//设置冻结修改延迟【毫秒】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("全局加速", "已关闭","Velocity","Close", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("全局加速|Velocity", false); + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xd269f8)+0x38)+0x770)+0x768)+0x1f8)+0x10;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("500", daddr, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return qjjsSwitchContentCard; + } + + +private SwitchContentCard createzdcqSwitchContentCard() { + final SwitchContentCard zdcqSwitchContentCard = new SwitchContentCard("子弹穿墙", "使发射的子弹可以穿透部分墙体").OText("子弹穿墙","使发射的子弹可以穿透部分墙体","Penetrate","Bullets go through walls.").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + zdcqSwitchContentCard.setExpandableContent(column); + + + + + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + zdcqShortcutButton.show(); + } else { + zdcqShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(zdcqSwitchContentCard, zdcqShortcutButton, new SwitchCallback() { + + + @Override + public boolean onChecked(boolean newState) { + + +Main.音效(); + + if (newState) { + +notification.make("子弹穿墙", "已开启","Penetrate","Open" ,Notification.Type.SUCCESS); + +ModuleManager.getInstance().setModuleEnabled("子弹穿墙|Penetrate", true); +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0xDCB5E8);//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("0", daddr, AlguiMemTool.TYPE_FLOAT,true,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + + } else { +notification.make("子弹穿墙", "已关闭", "Penetrate","Close",Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("子弹穿墙|Penetrate", false); + +AlguiMemTool.clearResultList();//清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial");//设置包名 +long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB);//获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr = AlguiMemTool.jump64(sAddr + 0xDCB5E8);//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("10", daddr, AlguiMemTool.TYPE_FLOAT,false,true);//修改目标值 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 修改完成 则清空这次的搜索结果 + + } + return true; + } + }); + + return zdcqSwitchContentCard; + } + +private SwitchContentCard createyichangSwitchContentCard() { + // 创建快捷键按钮 + final SwitchShortcutButton yichangShortcutButton = new SwitchShortcutButton().setText("异常发包器").OText("异常发包器", "Packet Emitter") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + + final SwitchContentCard yichangSwitchContentCard = new SwitchContentCard("异常发包器", "向服务器发出自身的异常坐标") .OText("异常发包器", "向服务器发出自身的异常坐标", "Outsourcing", "Send abnormal coordinates of itself to the server") + .setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + yichangSwitchContentCard.setExpandableContent(column); + + final Text reachText = new Text() + .setText("发包模式:","Outsourcing Mode:").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(5))); + column.addView(reachText); + + final RadioGroup radioGroup = new RadioGroup().setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + radioGroup.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent)); + + radioGroup.setEnabled(true); // 启用单选按钮组 + radioGroup.addButton("断开连接","kick","1"); // 添加第一个选项 + radioGroup.addButton("全图起飞","Fly", "2"); // 添加第三个选项 + final String[] selectedOption = { "1" }; // 默认选中第一个选项 + radioGroup.setRadioGroupCallback(new RadioGroupCallback() { + @Override + public void onChecked(String id) { + + } + }); + column.addView(radioGroup); // 将单选按钮组添加到内容区域 + + Widget divider = new Widget() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + .setTopMargin(dip2pxInt(15))) + .setBackgroundColor(hexColor("#40D0D0D0")); + column.addView(divider); + + SwitchContent shortcutSwitchContent = new SwitchContent("快捷键", "显示一个快捷按键以快速使用功能").OText("快捷键","显示一个快捷键以快速使用功能","FloatButton","Create a hover button").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + shortcutSwitchContent.setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + shortcutSwitchContent.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (newState) { + yichangShortcutButton.show(); + } else { + yichangShortcutButton.dismiss(); + } + return true; + } + }); + column.addView(shortcutSwitchContent); + + SyncUtil.sync(yichangSwitchContentCard, yichangShortcutButton, new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + + Main.音效(); + if (newState) { + + executeBehavior1(selectedOption[0], true); // 执行选中的行为 + +ModuleManager.getInstance().setModuleEnabled("异常发包器|Outsourcing", true); + notification.make("异常发包器", "已开启","Outsourcing","Open", Notification.Type.SUCCESS); + } else { + notification.make("异常发包器", "已关闭","Outsourcing","Open", Notification.Type.ERROR); +ModuleManager.getInstance().setModuleEnabled("异常发包器|Outsourcing", false); + executeBehavior1(selectedOption[0], false); // 停止执行行为 + + } + return true; + } + }); + + return yichangSwitchContentCard; + } + + + + + + private SwitchContentCard createskyboxSwitchContentCard() { + + final SwitchContentCard skyboxSwitchContentCard = new SwitchContentCard("天空盒坐标", "对天空盒进行坐标级平移").OText("天空盒坐标", "对天空盒进行坐标级平移","Skybox coordinates","Modify skybox coordinates").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang"); + final Column column = new Column() + .setLayoutParams(new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(15))); + skyboxSwitchContentCard.setExpandableContent(column); + + + Row distanceRow = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow); + + final Text distanceTitleText = new Text().setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang") + .setText("X轴:","X:") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceTitleText); + + final Text distanceText = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow.addView(distanceText); + + final Slider slider = new Slider(10000, -10000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xc62e90)+0x0)+0x540; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr1, AlguiMemTool.TYPE_FLOAT, false, true); + + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr1 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr1 = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr1 + 0xc62e90)+0x0)+0x540; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr1, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + } + } + + }); + column.addView(slider); + + Row distanceRow1 = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow1); + + final Text distanceTitleText1 = new Text() + .setText("Y轴:","Y:").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow1.addView(distanceTitleText1); + + final Text distanceText1 = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow1.addView(distanceText1); + + final Slider slider1 = new Slider(10000, -10000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText1.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc62e90)+0x0)+0x548; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText1.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x548; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true, true); + AlguiMemTool.setFreezeDelayMs(0); + + } + } + + }); + column.addView(slider1); + + Row distanceRow2 = new Row() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + column.addView(distanceRow2); + + final Text distanceTitleText2 = new Text() + .setText("Z轴:","Z").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow2.addView(distanceTitleText2); + + final Text distanceText2 = new Text() + .setText("暂无","You can't do this.").setLanguageSwitchFilePath("/sdcard/TC配置文件/switch.lang") + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + distanceRow2.addView(distanceText2); + + final Slider slider2 = new Slider(10000, -1000, 1000) + .setSliderCallback(new SliderCallback() { + + + + @SuppressLint("DefaultLocale") + @Override + public void onSlide(float newProgress, float oldProgress) { + distanceText2.setText(String.format(Locale.getDefault(), "%.1f", newProgress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x544; + AlguiMemTool.setMemoryAddrValue(""+newProgress, daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + } + + + + + @Override + public void onEnabled(boolean isEnabled, float progress) { + if (isEnabled) { + distanceText2.setText(String.format(Locale.getDefault(), "%.1f", progress)); + + AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr + 0xc62e90)+0x0)+0x544; + AlguiMemTool.setMemoryAddrValue(""+progress, daddr, AlguiMemTool.TYPE_FLOAT, true, true); + +AlguiMemTool.setFreezeDelayMs(0); + } + } + + }); + column.addView(slider2); + + + +skyboxSwitchContentCard.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { +slider.setEnabled(newState); + slider.setEnabled1(newState); + slider1.setEnabled(newState); + slider1.setEnabled1(newState); + slider2.setEnabled(newState); + slider2.setEnabled1(newState); +Main.音效(); + if (newState) { +ModuleManager.getInstance().setModuleEnabled("天空盒坐标|Skybox coordinates", true); + + + } else { +ModuleManager.getInstance().setModuleEnabled("天空盒坐标|Skybox coordinates", false); + + +AlguiMemTool.setPackageName("com.vortex.celestial"); + long sAddr = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", AlguiMemTool.HEAD_CB); + + + long daddr = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x540; + AlguiMemTool.setMemoryAddrValue("5", daddr, AlguiMemTool.TYPE_FLOAT, false, true); + + long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x544; + AlguiMemTool.setMemoryAddrValue("5", daddr2, AlguiMemTool.TYPE_FLOAT, false, true); + + long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr+ 0xc62e90)+0x0)+0x548; + AlguiMemTool.setMemoryAddrValue("5", daddr3, AlguiMemTool.TYPE_FLOAT, false, true); + + } + return true; + } + }); + + return skyboxSwitchContentCard; +} + + + + + + + + private void executeBehavior1(String selectedOption, boolean enable) { + if (enable) { + + ace.executeHiddenBinary(getAction1(selectedOption)); + + + } else { + + + ace.stopBinary(getCloseAction1(selectedOption)); + } + } + + + + + + private String getAction1(String option) {// 铁臂猎手 + switch (option) { + case "1": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x39E2E8) + 0x28) + 0x0) + + 0x70) + 0x68) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-25", daddr3, AlguiMemTool.TYPE_DWORD, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x380) + 0x1C0) + + 0x88) + 0x38) + 0xDC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-25", daddr2, AlguiMemTool.TYPE_DWORD, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + + + return "离线"; + + case "2": + AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr31 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr31 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr31 + 0x39E2E8) + 0x28) + 0x0) + + 0x70) + 0x68) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-41", daddr31, AlguiMemTool.TYPE_DWORD, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr21 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr21 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr21 + 0xDCBC30) + 0x380) + 0x1C0) + + 0x88) + 0x38) + 0xDC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("-41", daddr21, AlguiMemTool.TYPE_DWORD, true,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.setFreezeDelayMs(0);// 设置冻结修改延迟【毫秒】 + + + + return "起飞"; + + default: + return ""; + } + + } + +private String getCloseAction1(String option) { + + AlguiMemTool.clearResultList();// 清空之前的搜索结果 +AlguiMemTool.setPackageName("com.vortex.celestial"); +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr3 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr3 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr3 + 0x39E2E8) + 0x28) + 0x0) + + 0x70) + 0x68) + 0x16C;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9", daddr3, AlguiMemTool.TYPE_DWORD, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 + +AlguiMemTool.clearResultList();// 清空之前的搜索结果 +long sAddr2 = AlguiMemTool.getModuleBaseAddr("libclient.so:bss", + AlguiMemTool.HEAD_CB);// 获取模块基址 【xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 +long daddr2 = AlguiMemTool.jump64(AlguiMemTool.jump64(AlguiMemTool.jump64( + AlguiMemTool.jump64(AlguiMemTool.jump64(sAddr2 + 0xDCBC30) + 0x380) + 0x1C0) + + 0x88) + 0x38) + 0xDC;// 跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 +AlguiMemTool.setMemoryAddrValue("9", daddr2, AlguiMemTool.TYPE_DWORD, false,true);// 修改目标值 + // 【如果需要冻结将false改为true】 +AlguiMemTool.clearResultList();// 清空之前的搜索结果 + switch (option) { + case "1": + return "离线"; + case "2": + return "起飞"; + default: + return ""; + } + } + + + + + + + + + + + + + + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/ZipUtilT.java b/app/src/main/java/com/bytecat/algui/ui/category/ZipUtilT.java new file mode 100644 index 0000000..9ae273d --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/ZipUtilT.java @@ -0,0 +1,63 @@ +package com.bytecat.algui.ui.category; // ← 换成你自己的包名 + +import java.io.*; +import java.util.zip.*; + +public final class ZipUtilT { + + /** 把 srcDir 整个目录压缩成 zipFile */ + public static void zip(File srcDir, File zipFile) throws IOException { + if (!srcDir.exists()) return; + try (ZipOutputStream zos = new ZipOutputStream( + new BufferedOutputStream(new FileOutputStream(zipFile)))) { + zip(srcDir, "", zos); + } + } + + /** 递归压缩内部实现 */ + private static void zip(File srcDir, String base, ZipOutputStream zos) throws IOException { + File[] files = srcDir.listFiles(); + if (files == null) return; + + byte[] buf = new byte[8192]; + for (File f : files) { + String entryName = base + f.getName(); + if (f.isDirectory()) { + // 空目录也要写一条记录 + zos.putNextEntry(new ZipEntry(entryName + "/")); + zos.closeEntry(); + zip(f, entryName + "/", zos); + } else { + try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f))) { + zos.putNextEntry(new ZipEntry(entryName)); + int len; + while ((len = bis.read(buf)) != -1) zos.write(buf, 0, len); + zos.closeEntry(); + } + } + } + } + +/** 解压 zipFile 到 destDir */ +public static void unzip(File zipFile, File destDir) throws IOException { + try (ZipInputStream zis = new ZipInputStream( + new BufferedInputStream(new FileInputStream(zipFile)))) { + ZipEntry entry; + byte[] buffer = new byte[8192]; + while ((entry = zis.getNextEntry()) != null) { + File outFile = new File(destDir, entry.getName()); + if (entry.isDirectory()) { + outFile.mkdirs(); + } else { + outFile.getParentFile().mkdirs(); + try (FileOutputStream fos = new FileOutputStream(outFile)) { + int len; + while ((len = zis.read(buffer)) != -1) fos.write(buffer, 0, len); + } + } + zis.closeEntry(); + } + } +} + private ZipUtilT() {} // 禁止实例化 +} diff --git a/app/src/main/java/com/bytecat/algui/ui/category/aboutCategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/category/aboutCategoryBox.java new file mode 100644 index 0000000..ba92b64 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/category/aboutCategoryBox.java @@ -0,0 +1,39 @@ +package com.bytecat.algui.ui.category; + +import com.bytecat.algui.ui.component.CategoryBox; +import com.bytecat.algui.ui.component.TextContentCard; + +public class aboutCategoryBox extends CategoryBox { + + public aboutCategoryBox() { + contentContainer + .addView(createMixNewTextContentCard()) + .addView(createWhatIsMixTextContentCard()); + } + + private TextContentCard createMixNewTextContentCard() { + return new TextContentCard( +"关于UI:MIX - NEW", +"由苏沐橙(Su Mucheng)于2024年创建。\n"+ +"QQ:3578557729\n"+ +"QQ群:204677717\n"+ +"价格:100元人民币(恕不议价)\n"+ +"其他UI:MuCuteUI、MuCuteUIX(MIX)\n"+ +"注意事项:本UI基于MuCuteUIX开发,新增了众多组件,并优化了性能。" + ); + } + + private TextContentCard createWhatIsMixTextContentCard() { + return new TextContentCard( + "关于本项目:TrosCore", + "由凌白、龙图主力制作\n" + + "由小伙子加密及对接工具\n" + + "感谢半夢的支持与帮助\n" + + "使用TC客户端(更改地板等)\n" + + "更便宜的价格、更流畅的体验\n" + + "基于先前项目进行改进,使用了全新的UI\n" + + "QQ群:1030990452" + ); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/BoxButton.java b/app/src/main/java/com/bytecat/algui/ui/component/BoxButton.java new file mode 100644 index 0000000..dc1132c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/BoxButton.java @@ -0,0 +1,74 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.util.GradientDrawableBuilder; +import com.bytecat.algui.component.Stack; +import android.graphics.Typeface; +import com.bytecat.algui.layoutparams.StackParams; +import android.view.Gravity; + +public class BoxButton extends Stack { + public String buttonText; + + public Text text; + + private ClickCallback clickCallback; + + public BoxButton(String buttonText) { + this.buttonText = buttonText; + + setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#00000000")) + .setAllRadius(dip2px(8)) + ); + + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ); + + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (clickCallback != null) { + clickCallback.onClick(); + } + } + }); + + text = new Text() + .setText(buttonText) + .setTextSize(10f) + .setTextColor(hexColor("#00000000")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams( + new StackParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setGravity(Gravity.CENTER) + .setMargins(dip2pxInt(15), dip2pxInt(5), dip2pxInt(15), dip2pxInt(5)) + ); + addView(text); + } + + public BoxButton() { + this("button.common.run"); + } + + public BoxButton setClickCallback(ClickCallback clickCallback) { + this.clickCallback = clickCallback; + return this; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/BoxContent.java b/app/src/main/java/com/bytecat/algui/ui/component/BoxContent.java new file mode 100644 index 0000000..de2e915 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/BoxContent.java @@ -0,0 +1,107 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; +import android.graphics.Typeface; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Relative; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; +import android.widget.RelativeLayout; + +public class BoxContent extends Relative { + + public static final int BUTTON_ID = View.generateViewId(); + + public final String title; + public final String description; + + public Relative contentContainer; + public Column textContainer; + public Text titleText; + public Text descriptionText; + public BoxButton mButton; // 使用 Button + + public BoxContent(String title) { + this(title, null); + } + + public BoxContent(String title, String description) { + this(title, description, false); + } + + public BoxContent(String title, String description, boolean isChecked) { + this.title = title; + this.description = description; + + contentContainer = new Relative() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + addView(contentContainer); + + textContainer = new Column() + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setRightMargin(dip2pxInt(15)) + .addRule(RelativeLayout.START_OF, BUTTON_ID) + .addRule(RelativeLayout.CENTER_IN_PARENT) + ); + contentContainer.addView(textContainer); + + titleText = new Text() + .setSingleLine(true) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ) + .setText(title) + .setTextSize(12f) + .setTextColor(hexColor("#FF999999")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(titleText); + + if (description != null) { + descriptionText = new Text() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(2)) + ) + .setText(description) + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(descriptionText); + } + + + + + +mButton = new BoxButton(""); // 可以根据需要修改按钮文本 +mButton.setId(BUTTON_ID).setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.ALIGN_PARENT_RIGHT) + .addRule(RelativeLayout.CENTER_IN_PARENT) +); +contentContainer.addView(mButton); +} + + // 添加设置按钮点击回调的方法 + public BoxContent setButtonCallback(ClickCallback clickCallback) { + mButton.setClickCallback(clickCallback); + return this; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/ui/component/BoxContentCard.java b/app/src/main/java/com/bytecat/algui/ui/component/BoxContentCard.java new file mode 100644 index 0000000..06675f2 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/BoxContentCard.java @@ -0,0 +1,127 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; + +public class BoxContentCard extends ContentCard { + + public BoxContent BoxContent; + public Column expandableContentContainer; + public Widget divider; + public ViewHelper expandableContent; + public boolean isExpanded; + + // ===== 追加字段 ===== +private String chineseTitle; +private String chineseDescription; +private String englishTitle; +private String englishDescription; +private String languageSwitchFilePath; + +// ===== 追加 API ===== +public BoxContentCard OText(String chineseTitle, String chineseDescription, + String englishTitle, String englishDescription) { + this.chineseTitle = chineseTitle; + this.chineseDescription = chineseDescription; + this.englishTitle = englishTitle; + this.englishDescription = englishDescription; + return this; +} + +public BoxContentCard OText(String chineseTitle, String chineseDescription) { + return OText(chineseTitle, chineseDescription, null, null); +} + +public BoxContentCard setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; +} + +private void updateTextBasedOnFile() { + boolean fileExists = new java.io.File(languageSwitchFilePath).exists(); + if (fileExists) { + BoxContent.titleText.setText(chineseTitle); + if (BoxContent.descriptionText != null) { + BoxContent.descriptionText.setText(chineseDescription); + } + } else { + if (englishTitle != null && englishDescription != null) { + BoxContent.titleText.setText(englishTitle); + if (BoxContent.descriptionText != null) { + BoxContent.descriptionText.setText(englishDescription); + } + } + } +} + + public BoxContentCard(String title, String description, boolean isChecked) { + BoxContent = new BoxContent(title, description, isChecked); + BoxContent.setLayoutParams( + new LinearParams() + .setAllMargins(dip2pxInt(15)) + ); + addView(BoxContent); + + expandableContentContainer = new Column() + .setVisibility(View.GONE) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setMargins(dip2pxInt(15), 0, dip2pxInt(15), dip2pxInt(15)) + ); + addView(expandableContentContainer); + + divider = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + ) + .setBackgroundColor(hexColor("#40D0D0D0")); + expandableContentContainer.addView(divider); + } + + public BoxContentCard(String title, String description) { + this(title, description, false); + } + + public BoxContentCard(String title) { + this(title, null, false); + } + + public BoxContentCard setClickCallback(ClickCallback clickCallback) { + BoxContent.setButtonCallback(clickCallback); + return this; + } + + public BoxContentCard setExpandableContent(ViewHelper expandableContent) { + this.expandableContent = expandableContent; + if (expandableContent != null) { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (build().getLayoutTransition().isRunning()) { + return; + } + + isExpanded = !isExpanded; + if (isExpanded) { + expandableContentContainer.setVisibility(View.VISIBLE); + } else { + expandableContentContainer.setVisibility(View.GONE); + } + } + }); + expandableContentContainer.addView(expandableContent); + } + return this; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/ui/component/Button.java b/app/src/main/java/com/bytecat/algui/ui/component/Button.java new file mode 100644 index 0000000..115321c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/Button.java @@ -0,0 +1,74 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.util.GradientDrawableBuilder; +import com.bytecat.algui.component.Stack; +import android.graphics.Typeface; +import com.bytecat.algui.layoutparams.StackParams; +import android.view.Gravity; + +public class Button extends Stack { + public String buttonText; + + public Text text; + + private ClickCallback clickCallback; + + public Button(String buttonText) { + this.buttonText = buttonText; + + setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#B32C2C32")) + .setAllRadius(dip2px(8)) + ); + + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ); + + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (clickCallback != null) { + clickCallback.onClick(); + } + } + }); + + text = new Text() + .setText(buttonText) + .setTextSize(10f) + .setTextColor(hexColor("#FFA5A5A5")) + .setTypeface(Typeface.DEFAULT_BOLD) + .setLayoutParams( + new StackParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setGravity(Gravity.CENTER) + .setMargins(dip2pxInt(15), dip2pxInt(5), dip2pxInt(15), dip2pxInt(5)) + ); + addView(text); + } + + public Button() { + this("button.common.run"); + } + + public Button setClickCallback(ClickCallback clickCallback) { + this.clickCallback = clickCallback; + return this; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/ButtonContent.java b/app/src/main/java/com/bytecat/algui/ui/component/ButtonContent.java new file mode 100644 index 0000000..1560fb2 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/ButtonContent.java @@ -0,0 +1,113 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; +import android.graphics.Typeface; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Relative; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; +import android.widget.RelativeLayout; +import java.io.File; + +public class ButtonContent extends Relative { + + public static final int BUTTON_ID = View.generateViewId(); + + public final String title; + public final String description; + + public Relative contentContainer; + public Column textContainer; + public Text titleText; + public Text descriptionText; + public Button mButton; // 使用 Button + + public ButtonContent(String title) { + this(title, null); + } + + public ButtonContent(String title, String description) { + this(title, description, false); + } + + public ButtonContent(String title, String description, boolean isChecked) { + this.title = title; + this.description = description; + + contentContainer = new Relative() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + addView(contentContainer); + + textContainer = new Column() + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setRightMargin(dip2pxInt(15)) + .addRule(RelativeLayout.START_OF, BUTTON_ID) + .addRule(RelativeLayout.CENTER_IN_PARENT) + ); + contentContainer.addView(textContainer); + + titleText = new Text() + .setSingleLine(true) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ) + .setText(title) + .setTextSize(12f) + .setTextColor(hexColor("#FF999999")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(titleText); + + if (description != null) { + descriptionText = new Text() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(2)) + ) + .setText(description) + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(descriptionText); + } + + // 初始化 Button + // 初始化 Button + +String buttonText = "Run"; +String filePath ="/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; +File file = new File(filePath); +if (file.exists()) { +buttonText = "执行"; +} + +mButton = new Button(buttonText); // 可以根据需要修改按钮文本 +mButton.setId(BUTTON_ID).setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.ALIGN_PARENT_RIGHT) + .addRule(RelativeLayout.CENTER_IN_PARENT) +); +contentContainer.addView(mButton); +} + // 添加设置按钮点击回调的方法 + public ButtonContent setButtonCallback(ClickCallback clickCallback) { + mButton.setClickCallback(clickCallback); + return this; + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/ButtonContent.java.bak b/app/src/main/java/com/bytecat/algui/ui/component/ButtonContent.java.bak new file mode 100644 index 0000000..37711fb --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/ButtonContent.java.bak @@ -0,0 +1,113 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; +import android.graphics.Typeface; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Relative; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; +import android.widget.RelativeLayout; +import java.io.File; + +public class ButtonContent extends Relative { + + public static final int BUTTON_ID = View.generateViewId(); + + public final String title; + public final String description; + + public Relative contentContainer; + public Column textContainer; + public Text titleText; + public Text descriptionText; + public Button mButton; // 使用 Button + + public ButtonContent(String title) { + this(title, null); + } + + public ButtonContent(String title, String description) { + this(title, description, false); + } + + public ButtonContent(String title, String description, boolean isChecked) { + this.title = title; + this.description = description; + + contentContainer = new Relative() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + addView(contentContainer); + + textContainer = new Column() + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setRightMargin(dip2pxInt(15)) + .addRule(RelativeLayout.START_OF, BUTTON_ID) + .addRule(RelativeLayout.CENTER_IN_PARENT) + ); + contentContainer.addView(textContainer); + + titleText = new Text() + .setSingleLine(true) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ) + .setText(title) + .setTextSize(12f) + .setTextColor(hexColor("#FF999999")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(titleText); + + if (description != null) { + descriptionText = new Text() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(2)) + ) + .setText(description) + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(descriptionText); + } + + // 初始化 Button + // 初始化 Button + +String buttonText = "Run"; +String filePath ="/sdcard/TC配置文件/switch.lang"; +File file = new File(filePath); +if (file.exists()) { +buttonText = "执行"; +} + +mButton = new Button(buttonText); // 可以根据需要修改按钮文本 +mButton.setId(BUTTON_ID).setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.ALIGN_PARENT_RIGHT) + .addRule(RelativeLayout.CENTER_IN_PARENT) +); +contentContainer.addView(mButton); +} + // 添加设置按钮点击回调的方法 + public ButtonContent setButtonCallback(ClickCallback clickCallback) { + mButton.setClickCallback(clickCallback); + return this; + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/ButtonContentCard.java b/app/src/main/java/com/bytecat/algui/ui/component/ButtonContentCard.java new file mode 100644 index 0000000..bd4f76c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/ButtonContentCard.java @@ -0,0 +1,138 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; +import android.widget.RelativeLayout; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; + +import java.io.File; + +public class ButtonContentCard extends ContentCard { + + public ButtonContent buttonContent; + public Column expandableContentContainer; + public Widget divider; + public ViewHelper expandableContent; + public boolean isExpanded; + + // 中文文本 + private String chineseTitle; + private String chineseDescription; + + // 英文文本 + private String englishTitle; + private String englishDescription; + + // 文件路径 + private String languageSwitchFilePath; + + public ButtonContentCard(String title, String description, boolean isChecked) { + buttonContent = new ButtonContent(title, description, isChecked); + buttonContent.setLayoutParams( + new LinearParams() + .setAllMargins(BaseHelper.dip2pxInt(15)) + ); + addView(buttonContent); + + expandableContentContainer = new Column() + .setVisibility(View.GONE) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setMargins(BaseHelper.dip2pxInt(15), 0, BaseHelper.dip2pxInt(15), BaseHelper.dip2pxInt(15)) + ); + addView(expandableContentContainer); + + divider = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.dip2pxInt(1)) + ) + .setBackgroundColor(BaseHelper.hexColor("#B32C2C32")); + expandableContentContainer.addView(divider); + + // 初始化时直接设置中文文本 + updateTextBasedOnFile(); + } + + public ButtonContentCard(String title, String description) { + this(title, description, false); + } + + public ButtonContentCard(String title) { + this(title, null, false); + } + + public ButtonContentCard setClickCallback(ClickCallback clickCallback) { + buttonContent.setButtonCallback(clickCallback); + return this; + } + + public ButtonContentCard setExpandableContent(ViewHelper expandableContent) { + this.expandableContent = expandableContent; + if (expandableContent != null) { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (build().getLayoutTransition().isRunning()) { + return; + } + + isExpanded = !isExpanded; + if (isExpanded) { + expandableContentContainer.setVisibility(View.VISIBLE); + } else { + expandableContentContainer.setVisibility(View.GONE); + } + } + }); + expandableContentContainer.addView(expandableContent); + } + return this; + } + + // 设置中英文文本 + public ButtonContentCard OText(String chineseTitle, String chineseDescription, + String englishTitle, String englishDescription) { + this.chineseTitle = chineseTitle; + this.chineseDescription = chineseDescription; + this.englishTitle = englishTitle; + this.englishDescription = englishDescription; + updateTextBasedOnFile(); + return this; + } + + // 设置语言切换文件路径 + public ButtonContentCard setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; + } + + // 根据文件存在与否更新文本 + private void updateTextBasedOnFile() { + if (languageSwitchFilePath == null) return; + + boolean fileExists = new File(languageSwitchFilePath).exists(); + if (fileExists) { + buttonContent.titleText.setText(chineseTitle); + if (buttonContent.descriptionText != null) { + buttonContent.descriptionText.setText(chineseDescription); + } + } else { + buttonContent.titleText.setText(englishTitle); + if (buttonContent.descriptionText != null) { + buttonContent.descriptionText.setText(englishDescription); + } + } + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/CategoryBox.java b/app/src/main/java/com/bytecat/algui/ui/component/CategoryBox.java new file mode 100644 index 0000000..8ac2055 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/CategoryBox.java @@ -0,0 +1,33 @@ +package com.bytecat.algui.ui.component; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.ColumnScroll; +import com.bytecat.algui.layoutparams.LinearParams; + +public class CategoryBox extends ColumnScroll { + + public Column contentContainer; + + public CategoryBox() { + setScrollBarEnabled(false); + setFadingEdgeEnabled(true); + setFadingEdgeLength(dip2pxInt(8)); + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setTopMargin(dip2pxInt(10)) + .setBottomMargin(dip2pxInt(10)) + ); + + contentContainer = new Column() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + addView(contentContainer); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/CategoryCard.java b/app/src/main/java/com/bytecat/algui/ui/component/CategoryCard.java new file mode 100644 index 0000000..030f14d --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/CategoryCard.java @@ -0,0 +1,56 @@ +package com.bytecat.algui.ui.component; + +import android.graphics.Typeface; +import android.view.Gravity; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; + +public class CategoryCard extends Row { + + private String category; + + public Text categoryTitleText; + + public ViewHelper content; + + public CategoryCard setText(String category) { + this.category = category; + if (categoryTitleText != null) { + categoryTitleText.setText(category); + } + return this; + } + + public CategoryCard setContent(ViewHelper content) { + this.content = content; + return this; + } + + public CategoryCard() { + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(34)) + .setMargins(dip2pxInt(15), 0, dip2pxInt(15), 0) + ); + + categoryTitleText = new Text() + .setSingleLine(true) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + ) + .setGravity(Gravity.CENTER) + .setText(category) + .setTextSize(12f) + .setTextColor(hexColor("#DAFFFFFF")) + .setTypeface(Typeface.DEFAULT_BOLD); + addView(categoryTitleText); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/ContentCard.java b/app/src/main/java/com/bytecat/algui/ui/component/ContentCard.java new file mode 100644 index 0000000..da430e9 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/ContentCard.java @@ -0,0 +1,25 @@ +package com.bytecat.algui.ui.component; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.util.GradientDrawableBuilder; + +public class ContentCard extends Column { + + public ContentCard() { + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setMargins(0, dip2pxInt(5), 0, dip2pxInt(5)) + ); + setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#20D0D0D0")) + .setAllRadius(dip2px(10)) + ); + animatedContent(); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/RadioGroup.java b/app/src/main/java/com/bytecat/algui/ui/component/RadioGroup.java new file mode 100644 index 0000000..11f976a --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/RadioGroup.java @@ -0,0 +1,126 @@ +package com.bytecat.algui.ui.component; + +import java.util.LinkedHashMap; +import java.util.Map; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.callback.RadioGroupCallback; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.RowScroll; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.StackParams; + + +public class RadioGroup extends RowScroll { + + public Map map = new LinkedHashMap<>(); + + public Row row; + + private RadioGroupCallback radioGroupCallback; + + private boolean isEnabled = false; + + /* ===== 中英文切换 ===== */ + private String languageSwitchFilePath; + + public RadioGroup setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + return this; + } + + private boolean isChinese() { + return languageSwitchFilePath != null && new java.io.File(languageSwitchFilePath).exists(); + } + + public RadioGroup addButton(String chineseTitle, String englishTitle, final String id) { + return addButton(isChinese() ? chineseTitle : englishTitle, id); + } + + public RadioGroup() { + setScrollBarEnabled(false); + + row = new Row() + .setLayoutParams( + new StackParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ); + addView(row); + } + + public RadioGroup setChecked(String id) { + StatefulButton statefulButton = map.get(id); + if (statefulButton != null) { + statefulButton.setChecked(true); + for (String key : map.keySet()) { + StatefulButton value = map.get(key); + if (value != null && !key.equals(id)) { + value.setChecked(false); + } + } + } + return this; + } + + public RadioGroup setEnabled(boolean isEnabled) { + this.isEnabled = isEnabled; + return this; + } + + public RadioGroup addButton(String title, final String id) { + if (map.containsKey(id)) { + return this; + } + + final StatefulButton statefulButton = new StatefulButton(title); + statefulButton.setClickCallback(new ClickCallback() { + @Override + public void onClick() { + if (statefulButton.isChecked || !isEnabled) { + return; + } + + setChecked(id); + + if (radioGroupCallback != null) { + radioGroupCallback.onChecked(id); + } + } + }); + + if (!map.isEmpty()) { + statefulButton.setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(10)) + ); + } else { + statefulButton.setChecked(true); + } + map.put(id, statefulButton); + row.addView(statefulButton); + return this; + } + + public RadioGroup removeButton(String id) { + if (!map.containsKey(id)) { + return this; + } + + StatefulButton statefulButton = map.get(id); + if (statefulButton != null) { + map.remove(id); + row.removeView(statefulButton); + } + return this; + } + + public RadioGroup setRadioGroupCallback(RadioGroupCallback radioGroupCallback) { + this.radioGroupCallback = radioGroupCallback; + return this; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/Slider.java b/app/src/main/java/com/bytecat/algui/ui/component/Slider.java new file mode 100644 index 0000000..1e0f6fa --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/Slider.java @@ -0,0 +1,106 @@ +package com.bytecat.algui.ui.component; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.view.MotionEvent; +import android.view.*; + +import com.bytecat.algui.callback.SliderCallback; +import android.graphics.RectF; +import android.animation.ValueAnimator; +import com.bytecat.algui.component.BasicSlider; +import com.bytecat.algui.component.Card; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.layoutparams.StackParams; +import com.bytecat.algui.view.SliderView; + +public class Slider extends Card { + + public BasicSlider basicSlider; + + private boolean isEnabled; + + private interface DispatchCallback { + void onDispatch(float newProgress, float oldProgress); + } + + public Slider setSliderCallback(SliderCallback sliderCallback) { + basicSlider.setSliderCallback(sliderCallback); + return this; + } + + public Slider() { + this(100f, 0f); + } + + public Slider(float max, float progress) { + this(max, 0, progress); + } + + public Slider(float max, float min, float progress) { + setCardBackgroundColor(hexColor("#B32C2C32")); + setCardElevation(0f); + setRadius(dip2px(10)); + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(sp2pxInt(10)) + .setTopMargin(dip2pxInt(5)) + ); + + basicSlider = new BasicSlider() + .setLayoutParams( + new StackParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + ) + .setSliderParams(max, min, progress); + addView(basicSlider); + } + + public Slider setMax(float max) { + basicSlider.setMax(max); + return this; + } + + public Slider setMin(float min) { + basicSlider.setMin(min); + return this; + } + + public Slider setProgress(float progress) { + basicSlider.setProgress(progress); + return this; + } + + public Slider setSliderParams(float max, float min, float progress) { + basicSlider.setSliderParams(max, min, progress); + return this; + } + + public Slider setEnabled(boolean isEnabled) { + if (this.isEnabled != isEnabled) { + this.isEnabled = isEnabled; + final SliderView sliderView = basicSlider.sliderView; + final SliderCallback sliderCallback = sliderView.sliderCallback; + if (sliderCallback != null) { + float progress = basicSlider.sliderView.getProgress(); + sliderCallback.onEnabled(isEnabled, progress); + } + } + return this; + } + + + + public Slider setEnabled1(boolean isEnabled) { + basicSlider.setEnabled(isEnabled); + return this; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/StatefulButton.java b/app/src/main/java/com/bytecat/algui/ui/component/StatefulButton.java new file mode 100644 index 0000000..fc93f90 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/StatefulButton.java @@ -0,0 +1,218 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.animation.AnimatedSet; +import com.bytecat.algui.util.GradientDrawableBuilder; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.interpolator.FastOutSlowInInterpolator; +import com.bytecat.algui.animation.ValueAnimated; +import android.animation.ValueAnimator; + +import java.io.File; + +public class StatefulButton extends Button { + + public static final String UNCHECKED_BACKGROUND_COLOR = "#B34A4A50"; + public static final String CHECKED_BACKGROUND_COLOR = "#CC7F7FD5"; + public static final String UNCHECKED_TEXT_COLOR = "#B3A9A9B3"; + public static final String CHECKED_TEXT_COLOR = "#E6E0E0E6"; + + public boolean isChecked; + + private SwitchCallback switchCallback; + + private int currentBackgroundColor; + + private int currentTextColor; + + public AnimatedSet animatorSet; + + private String chineseText; + private String englishText; + private float chineseTextSize = 10f; // 中文文本大小 + private float englishTextSize = 10f; // 英文文本大小 + + private String languageSwitchFilePath; + + public StatefulButton(String buttonText, boolean isChecked) { + super(buttonText); + this.isChecked = isChecked; + + currentBackgroundColor = BaseHelper.hexColor(isChecked ? CHECKED_BACKGROUND_COLOR : UNCHECKED_BACKGROUND_COLOR); + currentTextColor = BaseHelper.hexColor(isChecked ? CHECKED_TEXT_COLOR : UNCHECKED_TEXT_COLOR); + + setBackground( + new GradientDrawableBuilder() + .setColor(currentBackgroundColor) + .setAllRadius(BaseHelper.dip2px(8)) + ); + + text.setTextColor(currentTextColor); + + setClickCallback(new ClickCallback() { + @Override + public void onClick() { + if (switchCallback != null && !switchCallback.onChecked(!StatefulButton.this.isChecked)) { + return; + } + + animated(!StatefulButton.this.isChecked); + } + }); + } + + public StatefulButton(String buttonText) { + this(buttonText, false); + } + + public StatefulButton() { + this("button.common.run"); + } + + // 新增构造函数,用于支持中英文标题 + public StatefulButton(String chineseText, String englishText, boolean isChecked) { + super(chineseText); // 默认显示中文 + this.isChecked = isChecked; + this.chineseText = chineseText; + this.englishText = englishText; + + currentBackgroundColor = BaseHelper.hexColor(isChecked ? CHECKED_BACKGROUND_COLOR : UNCHECKED_BACKGROUND_COLOR); + currentTextColor = BaseHelper.hexColor(isChecked ? CHECKED_TEXT_COLOR : UNCHECKED_TEXT_COLOR); + + setBackground( + new GradientDrawableBuilder() + .setColor(currentBackgroundColor) + .setAllRadius(BaseHelper.dip2px(8)) + + + + + ); + + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(10)) + ); + + text.setTextColor(currentTextColor); + // 设置中文文本大小 + text.setTextSize(chineseTextSize); + + // 设置语言切换文件路径 + languageSwitchFilePath = "/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; + + // 检查语言文件存在与否并更新文本 + updateTextBasedOnFile(); + + setClickCallback(new ClickCallback() { + @Override + public void onClick() { + if (switchCallback != null && !switchCallback.onChecked(!StatefulButton.this.isChecked)) { + return; + } + + animated(!StatefulButton.this.isChecked); + } + }); + } + + public StatefulButton setChecked(boolean isChecked) { + if (this.isChecked != isChecked) { + animated(isChecked); + } + return this; + } + + public StatefulButton setSwitchCallback(SwitchCallback switchCallback) { + this.switchCallback = switchCallback; + return this; + } + + private void animated(boolean isChecked) { + if (animatorSet != null && animatorSet.build().isRunning()) { + animatorSet.cancel(); + } + + this.isChecked = isChecked; + + int endBackgroundColor; + if (this.isChecked) { + endBackgroundColor = BaseHelper.hexColor(CHECKED_BACKGROUND_COLOR); + } else { + endBackgroundColor = BaseHelper.hexColor(UNCHECKED_BACKGROUND_COLOR); + } + + int endTextColor; + if (this.isChecked) { + endTextColor = BaseHelper.hexColor(CHECKED_TEXT_COLOR); + } else { + endTextColor = BaseHelper.hexColor(UNCHECKED_TEXT_COLOR); + } + + animatorSet = new AnimatedSet() + .setInterpolator(new FastOutSlowInInterpolator()) + .setDuration(100L) + .playTogether( + new ValueAnimated() + .ofArgb(currentBackgroundColor, endBackgroundColor) + .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int animatedValue = (int) animation.getAnimatedValue(); + setBackground( + new GradientDrawableBuilder() + .setColor(animatedValue) + .setAllRadius(BaseHelper.dip2px(8)) + ); + currentBackgroundColor = animatedValue; + } + }), + new ValueAnimated() + .ofArgb(currentTextColor, endTextColor) + .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int animatedValue = (int) animation.getAnimatedValue(); + text.setTextColor(animatedValue); + currentTextColor = animatedValue; + } + }) + ) + .start(); + } + + // 设置语言切换文件路径 + public StatefulButton setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; + } + + // 根据文件存在与否更新文本 + private void updateTextBasedOnFile() { + if (languageSwitchFilePath == null) return; + + boolean fileExists = new File(languageSwitchFilePath).exists(); + if (fileExists) { + text.setText(chineseText); + text.setTextSize(chineseTextSize); + // 设置中文按钮内间距 + + } else { + text.setText(englishText); + text.setTextSize(englishTextSize); + // 设置英文按钮内间距(更小) + + + } + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/StatefulButton.java.bak b/app/src/main/java/com/bytecat/algui/ui/component/StatefulButton.java.bak new file mode 100644 index 0000000..3f1bd63 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/StatefulButton.java.bak @@ -0,0 +1,218 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.animation.AnimatedSet; +import com.bytecat.algui.util.GradientDrawableBuilder; +import com.bytecat.algui.callback.ClickCallback; +import com.bytecat.algui.interpolator.FastOutSlowInInterpolator; +import com.bytecat.algui.animation.ValueAnimated; +import android.animation.ValueAnimator; + +import java.io.File; + +public class StatefulButton extends Button { + + public static final String UNCHECKED_BACKGROUND_COLOR = "#B34A4A50"; + public static final String CHECKED_BACKGROUND_COLOR = "#CC7F7FD5"; + public static final String UNCHECKED_TEXT_COLOR = "#B3A9A9B3"; + public static final String CHECKED_TEXT_COLOR = "#E6E0E0E6"; + + public boolean isChecked; + + private SwitchCallback switchCallback; + + private int currentBackgroundColor; + + private int currentTextColor; + + public AnimatedSet animatorSet; + + private String chineseText; + private String englishText; + private float chineseTextSize = 10f; // 中文文本大小 + private float englishTextSize = 10f; // 英文文本大小 + + private String languageSwitchFilePath; + + public StatefulButton(String buttonText, boolean isChecked) { + super(buttonText); + this.isChecked = isChecked; + + currentBackgroundColor = BaseHelper.hexColor(isChecked ? CHECKED_BACKGROUND_COLOR : UNCHECKED_BACKGROUND_COLOR); + currentTextColor = BaseHelper.hexColor(isChecked ? CHECKED_TEXT_COLOR : UNCHECKED_TEXT_COLOR); + + setBackground( + new GradientDrawableBuilder() + .setColor(currentBackgroundColor) + .setAllRadius(BaseHelper.dip2px(8)) + ); + + text.setTextColor(currentTextColor); + + setClickCallback(new ClickCallback() { + @Override + public void onClick() { + if (switchCallback != null && !switchCallback.onChecked(!StatefulButton.this.isChecked)) { + return; + } + + animated(!StatefulButton.this.isChecked); + } + }); + } + + public StatefulButton(String buttonText) { + this(buttonText, false); + } + + public StatefulButton() { + this("button.common.run"); + } + + // 新增构造函数,用于支持中英文标题 + public StatefulButton(String chineseText, String englishText, boolean isChecked) { + super(chineseText); // 默认显示中文 + this.isChecked = isChecked; + this.chineseText = chineseText; + this.englishText = englishText; + + currentBackgroundColor = BaseHelper.hexColor(isChecked ? CHECKED_BACKGROUND_COLOR : UNCHECKED_BACKGROUND_COLOR); + currentTextColor = BaseHelper.hexColor(isChecked ? CHECKED_TEXT_COLOR : UNCHECKED_TEXT_COLOR); + + setBackground( + new GradientDrawableBuilder() + .setColor(currentBackgroundColor) + .setAllRadius(BaseHelper.dip2px(8)) + + + + + ); + + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setLeftMargin(dip2pxInt(10)) + ); + + text.setTextColor(currentTextColor); + // 设置中文文本大小 + text.setTextSize(chineseTextSize); + + // 设置语言切换文件路径 + languageSwitchFilePath = "/sdcard/TC配置文件/switch.lang"; + + // 检查语言文件存在与否并更新文本 + updateTextBasedOnFile(); + + setClickCallback(new ClickCallback() { + @Override + public void onClick() { + if (switchCallback != null && !switchCallback.onChecked(!StatefulButton.this.isChecked)) { + return; + } + + animated(!StatefulButton.this.isChecked); + } + }); + } + + public StatefulButton setChecked(boolean isChecked) { + if (this.isChecked != isChecked) { + animated(isChecked); + } + return this; + } + + public StatefulButton setSwitchCallback(SwitchCallback switchCallback) { + this.switchCallback = switchCallback; + return this; + } + + private void animated(boolean isChecked) { + if (animatorSet != null && animatorSet.build().isRunning()) { + animatorSet.cancel(); + } + + this.isChecked = isChecked; + + int endBackgroundColor; + if (this.isChecked) { + endBackgroundColor = BaseHelper.hexColor(CHECKED_BACKGROUND_COLOR); + } else { + endBackgroundColor = BaseHelper.hexColor(UNCHECKED_BACKGROUND_COLOR); + } + + int endTextColor; + if (this.isChecked) { + endTextColor = BaseHelper.hexColor(CHECKED_TEXT_COLOR); + } else { + endTextColor = BaseHelper.hexColor(UNCHECKED_TEXT_COLOR); + } + + animatorSet = new AnimatedSet() + .setInterpolator(new FastOutSlowInInterpolator()) + .setDuration(100L) + .playTogether( + new ValueAnimated() + .ofArgb(currentBackgroundColor, endBackgroundColor) + .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int animatedValue = (int) animation.getAnimatedValue(); + setBackground( + new GradientDrawableBuilder() + .setColor(animatedValue) + .setAllRadius(BaseHelper.dip2px(8)) + ); + currentBackgroundColor = animatedValue; + } + }), + new ValueAnimated() + .ofArgb(currentTextColor, endTextColor) + .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int animatedValue = (int) animation.getAnimatedValue(); + text.setTextColor(animatedValue); + currentTextColor = animatedValue; + } + }) + ) + .start(); + } + + // 设置语言切换文件路径 + public StatefulButton setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; + } + + // 根据文件存在与否更新文本 + private void updateTextBasedOnFile() { + if (languageSwitchFilePath == null) return; + + boolean fileExists = new File(languageSwitchFilePath).exists(); + if (fileExists) { + text.setText(chineseText); + text.setTextSize(chineseTextSize); + // 设置中文按钮内间距 + + } else { + text.setText(englishText); + text.setTextSize(englishTextSize); + // 设置英文按钮内间距(更小) + + + } + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/Switch.java b/app/src/main/java/com/bytecat/algui/ui/component/Switch.java new file mode 100644 index 0000000..f2b5939 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/Switch.java @@ -0,0 +1,146 @@ +package com.bytecat.algui.ui.component; + +import android.animation.ValueAnimator; +import android.view.View; + +import com.bytecat.algui.animation.AnimatedSet; +import com.bytecat.algui.animation.ValueAnimated; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Stack; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.interpolator.FastOutSlowInInterpolator; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.StackParams; +import com.bytecat.algui.util.GradientDrawableBuilder; + +public class Switch extends Stack { + + public static final String UNCHECKED_COLOR = "#B34A4A50"; +//UNCHECKED_COLOR = "#B34A4A50"; // 70 % 不透冷灰 + //CHECKED_COLOR = "#CC7F7FD5"; // 80 % 不透淡紫 + //circleColor = "#E6E0E0E6"; // 90 % 不透雾白 + + + public static final String CHECKED_COLOR = "#CC7F7FD5"; + + public boolean isChecked; + + public int currentBackgroundColor; + + public Widget circle; + + public AnimatedSet animatorSet; + + private SwitchCallback switchCallback; + + public Switch() { + this(false); + } + + public Switch(boolean isChecked) { + this.isChecked = isChecked; + setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ); + + currentBackgroundColor = hexColor(isChecked ? CHECKED_COLOR : UNCHECKED_COLOR); + setBackground( + new GradientDrawableBuilder() + .setColor(currentBackgroundColor) + .setAllRadius(dip2px(30)) + ); + + circle = new Widget() + .setTranslationX(isChecked ? dip2px(10) : -dip2px(10)) + .setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#E6E0E0E6")) + .setAllRadius(dip2px(15)) + ) + .setLayoutParams( + new StackParams() + .setWidth(dip2pxInt(12)) + .setHeight(dip2pxInt(12)) + .setMargins(dip2pxInt(15), dip2pxInt(5), dip2pxInt(15), dip2pxInt(5)) + ); + addView(circle); + + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (switchCallback != null && !switchCallback.onChecked(!Switch.this.isChecked)) { + return; + } + + animated(!Switch.this.isChecked); + } + }); + } + + public Switch setChecked(boolean isChecked) { + if (this.isChecked != isChecked) { + animated(isChecked); + } + return this; + } + + public Switch setSwitchCallback(SwitchCallback switchCallback) { + this.switchCallback = switchCallback; + return this; + } + + private void animated(boolean isChecked) { + if (animatorSet != null && animatorSet.build().isRunning()) { + animatorSet.cancel(); + } + + this.isChecked = isChecked; + float endX; + if (this.isChecked) { + endX = dip2px(10); + } else { + endX = -dip2px(10); + } + + int endColor; + if (this.isChecked) { + endColor = hexColor(CHECKED_COLOR); + } else { + endColor = hexColor(UNCHECKED_COLOR); + } + + animatorSet = new AnimatedSet() + .setInterpolator(new FastOutSlowInInterpolator()) + .setDuration(200L) + .playTogether( + new ValueAnimated() + .ofFloat(circle.build().getTranslationX(), endX) + .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + circle.setTranslationX(animatedValue); + } + }), + new ValueAnimated() + .ofArgb(currentBackgroundColor, endColor) + .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int animatedValue = (int) animation.getAnimatedValue(); + setBackground( + new GradientDrawableBuilder() + .setColor(animatedValue) + .setAllRadius(dip2px(30)) + ); + currentBackgroundColor = animatedValue; + } + }) + ) + .start(); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/SwitchContent.java b/app/src/main/java/com/bytecat/algui/ui/component/SwitchContent.java new file mode 100644 index 0000000..01e20ba --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/SwitchContent.java @@ -0,0 +1,165 @@ +package com.bytecat.algui.ui.component; + +import android.graphics.Typeface; +import android.view.View; +import android.widget.RelativeLayout; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Relative; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; + +import java.io.File; + +public class SwitchContent extends Relative { + + public static final String DEFAULT_LANGUAGE_SWITCH_FILE_PATH = + "/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; + public static final int SWITCH_ID = View.generateViewId(); + + public final String title; + public final String description; + + public Relative contentContainer; + public Column textContainer; + public Text titleText; + public Text descriptionText; + public Switch mSwitch; + + // 中文文本 + private String chineseTitle; + private String chineseDescription; + + // 英文文本 + private String englishTitle; + private String englishDescription; + + // 文件路径 + private String languageSwitchFilePath; + + public SwitchContent(String title) { + this(title, null); + } + + public SwitchContent(String title, String description) { + this(title, description, false); + } + + public SwitchContent(String title, String description, boolean isChecked) { + this.title = title; + this.description = description; + + contentContainer = new Relative() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + addView(contentContainer); + + textContainer = new Column() + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setRightMargin(dip2pxInt(15)) + .addRule(RelativeLayout.START_OF, SWITCH_ID) + .addRule(RelativeLayout.CENTER_IN_PARENT) + ); + contentContainer.addView(textContainer); + + titleText = new Text() + .setSingleLine(true) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ) + .setText(title) + .setTextSize(12f) + .setTextColor(hexColor("#DAFFFFFF")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(titleText); + + if (description != null) { + descriptionText = new Text() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(2)) + ) + .setText(description) + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(descriptionText); + } + + mSwitch = new Switch(isChecked); + mSwitch.setId(SWITCH_ID).setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.ALIGN_PARENT_RIGHT) + .addRule(RelativeLayout.CENTER_IN_PARENT) + ); + contentContainer.addView(mSwitch); + updateTextBasedOnFile(); + } + + public boolean newState() { + return false; + } + + public SwitchContent setChecked(boolean isChecked) { + mSwitch.setChecked(isChecked); + return this; + } + + public SwitchContent setSwitchCallback(SwitchCallback switchCallback) { + mSwitch.setSwitchCallback(switchCallback); + return this; + } + + // 设置中英文文本 + public SwitchContent OText(String chineseTitle, String chineseDescription, String englishTitle, String englishDescription) { + this.chineseTitle = chineseTitle; + this.chineseDescription = chineseDescription; + this.englishTitle = englishTitle; + this.englishDescription = englishDescription; + return this; + } + + // 设置语言切换文件路径 + public SwitchContent setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; + } + + // 根据文件存在与否更新文本 + private void updateTextBasedOnFile() { + // 1. 取自定义路径,没有则用默认路径 + String path = languageSwitchFilePath != null + ? languageSwitchFilePath + : DEFAULT_LANGUAGE_SWITCH_FILE_PATH; + + // 2. 如果中英文都未设置,直接 return,避免 NPE + if (chineseTitle == null && englishTitle == null) return; + + boolean fileExists = new File(path).exists(); + + // 3. 选择对应语言 + String titleTarget = fileExists ? chineseTitle : englishTitle; + String descTarget = fileExists ? chineseDescription : englishDescription; + + if (titleTarget != null) titleText.setText(titleTarget); + if (descriptionText != null && descTarget != null) { + descriptionText.setText(descTarget); + } + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/SwitchContent.java.bak b/app/src/main/java/com/bytecat/algui/ui/component/SwitchContent.java.bak new file mode 100644 index 0000000..2e93c9b --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/SwitchContent.java.bak @@ -0,0 +1,165 @@ +package com.bytecat.algui.ui.component; + +import android.graphics.Typeface; +import android.view.View; +import android.widget.RelativeLayout; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Relative; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; + +import java.io.File; + +public class SwitchContent extends Relative { + + public static final String DEFAULT_LANGUAGE_SWITCH_FILE_PATH = + "/sdcard/TC配置文件/switch.lang"; + public static final int SWITCH_ID = View.generateViewId(); + + public final String title; + public final String description; + + public Relative contentContainer; + public Column textContainer; + public Text titleText; + public Text descriptionText; + public Switch mSwitch; + + // 中文文本 + private String chineseTitle; + private String chineseDescription; + + // 英文文本 + private String englishTitle; + private String englishDescription; + + // 文件路径 + private String languageSwitchFilePath; + + public SwitchContent(String title) { + this(title, null); + } + + public SwitchContent(String title, String description) { + this(title, description, false); + } + + public SwitchContent(String title, String description, boolean isChecked) { + this.title = title; + this.description = description; + + contentContainer = new Relative() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + addView(contentContainer); + + textContainer = new Column() + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setRightMargin(dip2pxInt(15)) + .addRule(RelativeLayout.START_OF, SWITCH_ID) + .addRule(RelativeLayout.CENTER_IN_PARENT) + ); + contentContainer.addView(textContainer); + + titleText = new Text() + .setSingleLine(true) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ) + .setText(title) + .setTextSize(12f) + .setTextColor(hexColor("#DAFFFFFF")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(titleText); + + if (description != null) { + descriptionText = new Text() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(2)) + ) + .setText(description) + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(descriptionText); + } + + mSwitch = new Switch(isChecked); + mSwitch.setId(SWITCH_ID).setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.ALIGN_PARENT_RIGHT) + .addRule(RelativeLayout.CENTER_IN_PARENT) + ); + contentContainer.addView(mSwitch); + updateTextBasedOnFile(); + } + + public boolean newState() { + return false; + } + + public SwitchContent setChecked(boolean isChecked) { + mSwitch.setChecked(isChecked); + return this; + } + + public SwitchContent setSwitchCallback(SwitchCallback switchCallback) { + mSwitch.setSwitchCallback(switchCallback); + return this; + } + + // 设置中英文文本 + public SwitchContent OText(String chineseTitle, String chineseDescription, String englishTitle, String englishDescription) { + this.chineseTitle = chineseTitle; + this.chineseDescription = chineseDescription; + this.englishTitle = englishTitle; + this.englishDescription = englishDescription; + return this; + } + + // 设置语言切换文件路径 + public SwitchContent setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; + } + + // 根据文件存在与否更新文本 + private void updateTextBasedOnFile() { + // 1. 取自定义路径,没有则用默认路径 + String path = languageSwitchFilePath != null + ? languageSwitchFilePath + : DEFAULT_LANGUAGE_SWITCH_FILE_PATH; + + // 2. 如果中英文都未设置,直接 return,避免 NPE + if (chineseTitle == null && englishTitle == null) return; + + boolean fileExists = new File(path).exists(); + + // 3. 选择对应语言 + String titleTarget = fileExists ? chineseTitle : englishTitle; + String descTarget = fileExists ? chineseDescription : englishDescription; + + if (titleTarget != null) titleText.setText(titleTarget); + if (descriptionText != null && descTarget != null) { + descriptionText.setText(descTarget); + } + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/SwitchContentCard.java b/app/src/main/java/com/bytecat/algui/ui/component/SwitchContentCard.java new file mode 100644 index 0000000..2fe2d26 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/SwitchContentCard.java @@ -0,0 +1,174 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; +import android.widget.RelativeLayout; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; + +import java.io.File; + +public class SwitchContentCard extends ContentCard { + + + + public SwitchContent switchContent; + + public Column expandableContentContainer; + + + // 统一默认语言切换文件路径 + private static final String DEFAULT_LANGUAGE_SWITCH_FILE_PATH = "/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; + + + public Widget divider; + + public ViewHelper expandableContent; + + public boolean isExpanded; + + // 中文文本 + private String chineseTitle; + private String chineseDescription; + + // 英文文本 + private String englishTitle; + private String englishDescription; + + // 文件路径 + private String languageSwitchFilePath; + + + public SwitchContentCard(String title, String description, boolean isChecked) { + switchContent = new SwitchContent(title, description, isChecked); + switchContent.setLayoutParams( + new LinearParams() + .setAllMargins(dip2pxInt(15)) + ); + addView(switchContent); + + expandableContentContainer = new Column() + .setVisibility(View.GONE) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setMargins(dip2pxInt(15), 0, dip2pxInt(15), dip2pxInt(15)) + ); + addView(expandableContentContainer); + + divider = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + ) + .setBackgroundColor(hexColor("#40D0D0D0")); + expandableContentContainer.addView(divider); + + // ↓↓↓ 自动使用统一路径刷新文本 + updateTextBasedOnFile(); + } + + public SwitchContentCard(String title, String description) { + this(title, description, false); + } + + public SwitchContentCard(String title) { + this(title, null, false); + } + + public void setClickCallback(Object onClick) { + } + + public SwitchContentCard setExpandableContent(ViewHelper expandableContent) { + this.expandableContent = expandableContent; + if (expandableContent != null) { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (build().getLayoutTransition().isRunning()) { + return; + } + + isExpanded = !isExpanded; + if (isExpanded) { + expandableContentContainer.setVisibility(View.VISIBLE); + } else { + expandableContentContainer.setVisibility(View.GONE); + } + } + }); + expandableContentContainer.addView(expandableContent); + } + return this; + } + + public SwitchContentCard setSwitchCallback(SwitchCallback switchCallback) { + switchContent.setSwitchCallback(switchCallback); + return this; + } + + public SwitchContentCard setChecked(boolean isChecked) { + switchContent.setChecked(isChecked); + return this; + } + + // 设置中英文文本 + public SwitchContentCard OText(String chineseTitle, String chineseDescription, + String englishTitle, String englishDescription) { + this.chineseTitle = chineseTitle; + this.chineseDescription = chineseDescription; + this.englishTitle = englishTitle; + this.englishDescription = englishDescription; + updateTextBasedOnFile(); + return this; + } + + // 只设置中文文本 + public SwitchContentCard OText(String chineseTitle, String chineseDescription) { + this.chineseTitle = chineseTitle; + this.chineseDescription = chineseDescription; + return this; + } + + // 设置语言切换文件路径 + public SwitchContentCard setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; + } + + // 根据文件存在与否更新文本 + private void updateTextBasedOnFile() { + // 用实例路径,没有则用统一路径 + String path = languageSwitchFilePath != null ? languageSwitchFilePath + : DEFAULT_LANGUAGE_SWITCH_FILE_PATH; + boolean fileExists = new java.io.File(path).exists(); + + String titleTarget = fileExists ? chineseTitle : englishTitle; + String descTarget = fileExists ? chineseDescription : englishDescription; + + if (titleTarget != null) switchContent.titleText.setText(titleTarget); + if (switchContent.descriptionText != null && descTarget != null) { + switchContent.descriptionText.setText(descTarget); + } + } + + // 保留原有的构造方式 + public static SwitchContentCard create(String title, String description, boolean isChecked) { + return new SwitchContentCard(title, description, isChecked); + } + + public static SwitchContentCard create(String title, String description) { + return new SwitchContentCard(title, description); + } + + public static SwitchContentCard create(String title) { + return new SwitchContentCard(title); + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/SwitchContentCard.java.bak b/app/src/main/java/com/bytecat/algui/ui/component/SwitchContentCard.java.bak new file mode 100644 index 0000000..e238553 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/SwitchContentCard.java.bak @@ -0,0 +1,174 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; +import android.widget.RelativeLayout; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; + +import java.io.File; + +public class SwitchContentCard extends ContentCard { + + + + public SwitchContent switchContent; + + public Column expandableContentContainer; + + + // 统一默认语言切换文件路径 + private static final String DEFAULT_LANGUAGE_SWITCH_FILE_PATH = "/sdcard/TC配置文件/switch.lang"; + + + public Widget divider; + + public ViewHelper expandableContent; + + public boolean isExpanded; + + // 中文文本 + private String chineseTitle; + private String chineseDescription; + + // 英文文本 + private String englishTitle; + private String englishDescription; + + // 文件路径 + private String languageSwitchFilePath; + + + public SwitchContentCard(String title, String description, boolean isChecked) { + switchContent = new SwitchContent(title, description, isChecked); + switchContent.setLayoutParams( + new LinearParams() + .setAllMargins(dip2pxInt(15)) + ); + addView(switchContent); + + expandableContentContainer = new Column() + .setVisibility(View.GONE) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setMargins(dip2pxInt(15), 0, dip2pxInt(15), dip2pxInt(15)) + ); + addView(expandableContentContainer); + + divider = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + ) + .setBackgroundColor(hexColor("#40D0D0D0")); + expandableContentContainer.addView(divider); + + // ↓↓↓ 自动使用统一路径刷新文本 + updateTextBasedOnFile(); + } + + public SwitchContentCard(String title, String description) { + this(title, description, false); + } + + public SwitchContentCard(String title) { + this(title, null, false); + } + + public void setClickCallback(Object onClick) { + } + + public SwitchContentCard setExpandableContent(ViewHelper expandableContent) { + this.expandableContent = expandableContent; + if (expandableContent != null) { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (build().getLayoutTransition().isRunning()) { + return; + } + + isExpanded = !isExpanded; + if (isExpanded) { + expandableContentContainer.setVisibility(View.VISIBLE); + } else { + expandableContentContainer.setVisibility(View.GONE); + } + } + }); + expandableContentContainer.addView(expandableContent); + } + return this; + } + + public SwitchContentCard setSwitchCallback(SwitchCallback switchCallback) { + switchContent.setSwitchCallback(switchCallback); + return this; + } + + public SwitchContentCard setChecked(boolean isChecked) { + switchContent.setChecked(isChecked); + return this; + } + + // 设置中英文文本 + public SwitchContentCard OText(String chineseTitle, String chineseDescription, + String englishTitle, String englishDescription) { + this.chineseTitle = chineseTitle; + this.chineseDescription = chineseDescription; + this.englishTitle = englishTitle; + this.englishDescription = englishDescription; + updateTextBasedOnFile(); + return this; + } + + // 只设置中文文本 + public SwitchContentCard OText(String chineseTitle, String chineseDescription) { + this.chineseTitle = chineseTitle; + this.chineseDescription = chineseDescription; + return this; + } + + // 设置语言切换文件路径 + public SwitchContentCard setLanguageSwitchFilePath(String filePath) { + this.languageSwitchFilePath = filePath; + updateTextBasedOnFile(); + return this; + } + + // 根据文件存在与否更新文本 + private void updateTextBasedOnFile() { + // 用实例路径,没有则用统一路径 + String path = languageSwitchFilePath != null ? languageSwitchFilePath + : DEFAULT_LANGUAGE_SWITCH_FILE_PATH; + boolean fileExists = new java.io.File(path).exists(); + + String titleTarget = fileExists ? chineseTitle : englishTitle; + String descTarget = fileExists ? chineseDescription : englishDescription; + + if (titleTarget != null) switchContent.titleText.setText(titleTarget); + if (switchContent.descriptionText != null && descTarget != null) { + switchContent.descriptionText.setText(descTarget); + } + } + + // 保留原有的构造方式 + public static SwitchContentCard create(String title, String description, boolean isChecked) { + return new SwitchContentCard(title, description, isChecked); + } + + public static SwitchContentCard create(String title, String description) { + return new SwitchContentCard(title, description); + } + + public static SwitchContentCard create(String title) { + return new SwitchContentCard(title); + } +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/TextContent.java b/app/src/main/java/com/bytecat/algui/ui/component/TextContent.java new file mode 100644 index 0000000..48dd0d5 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/TextContent.java @@ -0,0 +1,84 @@ +package com.bytecat.algui.ui.component; + +import android.graphics.Typeface; +import android.widget.RelativeLayout; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Relative; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; + +public class TextContent extends Relative { + + public final String title; + + public final String description; + + public Relative contentContainer; + + public Column textContainer; + + public Text titleText; + + public Text descriptionText; + + public TextContent(String title) { + this(title, null); + } + + public TextContent(String title, String description) { + this.title = title; + this.description = description; + + contentContainer = new Relative() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + ); + addView(contentContainer); + + textContainer = new Column() + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setRightMargin(dip2pxInt(15)) + .addRule(RelativeLayout.ALIGN_PARENT_LEFT) + .addRule(RelativeLayout.CENTER_IN_PARENT) + ); + contentContainer.addView(textContainer); + + titleText = new Text() + .setSingleLine(true) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + ) + .setText(title) + .setTextSize(12f) + .setTextColor(hexColor("#FF999999")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(titleText); + + if (description != null) { + descriptionText = new Text() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(2)) + ) + .setText(description) + .setTextSize(10f) + .setTextColor(hexColor("#FFC5C5C5")) + .setTypeface(Typeface.DEFAULT_BOLD); + textContainer.addView(descriptionText); + } + + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/component/TextContentCard.java b/app/src/main/java/com/bytecat/algui/ui/component/TextContentCard.java new file mode 100644 index 0000000..020225c --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/component/TextContentCard.java @@ -0,0 +1,78 @@ +package com.bytecat.algui.ui.component; + +import android.view.View; + +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.layoutparams.LinearParams; + +public class TextContentCard extends ContentCard { + + public TextContent textContent; + + public Column expandableContentContainer; + + public Widget divider; + + public ViewHelper expandableContent; + + public boolean isExpanded; + + public TextContentCard(String title, String description) { + textContent = new TextContent(title, description); + textContent.setLayoutParams( + new LinearParams() + .setAllMargins(dip2pxInt(15)) + ); + addView(textContent); + + expandableContentContainer = new Column() + .setVisibility(View.GONE) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setMargins(dip2pxInt(15), 0, dip2pxInt(15), dip2pxInt(15)) + ); + addView(expandableContentContainer); + + divider = new Widget() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(1)) + ) + .setBackgroundColor(hexColor("#40D0D0D0")); + expandableContentContainer.addView(divider); + } + + public TextContentCard(String title) { + this(title, null); + } + + public TextContentCard setExpandableContent(ViewHelper expandableContent) { + this.expandableContent = expandableContent; + if (expandableContent != null) { + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (build().getLayoutTransition().isRunning()) { + return; + } + + isExpanded = !isExpanded; + if (isExpanded) { + expandableContentContainer.setVisibility(View.VISIBLE); + } else { + expandableContentContainer.setVisibility(View.GONE); + } + } + }); + expandableContentContainer.addView(expandableContent); + } + return this; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/gui/ClickGUI.java b/app/src/main/java/com/bytecat/algui/ui/gui/ClickGUI.java new file mode 100644 index 0000000..c3be935 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/gui/ClickGUI.java @@ -0,0 +1,403 @@ +package com.bytecat.algui.ui.gui; + +import android.graphics.Typeface; +import android.view.View; +import android.widget.RelativeLayout; + +import com.bytecat.algui.animation.ValueAnimated; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.ColumnScroll; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Relative; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Stack; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.interpolator.FastOutSlowInInterpolator; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; +import com.bytecat.algui.layoutparams.StackParams; +import com.bytecat.algui.ui.button.FloatButton; +import com.bytecat.algui.ui.category.aboutCategoryBox; +import com.bytecat.algui.ui.category.MiscCategoryBox; +import com.bytecat.algui.ui.category.PlayerCategoryBox; +import com.bytecat.algui.ui.category.AttackCategoryBox; +import com.bytecat.algui.ui.category.SettingCategoryBox; + + +import com.bytecat.algui.ui.category.WorldCategoryBox; +import com.bytecat.algui.ui.component.CategoryCard; +import com.bytecat.algui.util.GradientDrawableBuilder; + +import java.util.ArrayList; +import java.util.List; +import android.content.Context; +import android.graphics.Bitmap; +import com.bytecat.algui.view.BlurHelper; +import android.app.Activity; +import android.graphics.drawable.BitmapDrawable; +import android.view.Window; +import java.lang.ref.WeakReference; +import com.bytecat.algui.AlguiWindows.AlguiWin2FA; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import java.util.HashMap; +import com.bytecat.algui.AlguiTools.AlguiToolNative; +import com.topjohnwu.superuser.ipc.RootService; +import android.content.Intent; +import com.bytecat.algui.AlguiHacker.AlguiRootClient; +import android.os.AsyncTask; +import com.bytecat.algui.AlguiTools.AlguiToolNetwork; +import com.bytecat.algui.AlguiManager.AlguiDocument; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiHacker.AlguiRootService; +import com.bytecat.algui.MainActivity; +import android.graphics.drawable.GradientDrawable; +import com.bytecat.algui.ui.category.TPCategoryBox; +import com.bytecat.algui.ui.category.SettingCategoryBox; +import java.util.Map; +import java.util.LinkedHashMap; +import com.bytecat.algui.ui.category.ESPCategoryBox; +import com.bytecat.algui.ui.category.SpecialCategoryBox; +import com.bytecat.algui.ui.category.*; + +public class ClickGUI extends Popup { + + private Context context; + + public static final int MIX_TITLE_TEXT_ID = View.generateViewId(); + + public FloatButton floatButton; + + public List categoryCardList; + + public Column maskContainer; + + public Row panelContainer; + + public Column categoryUIContainer; + + public Relative mixContainer; + + public Text mixTitleText; + + public Text mixSubTitleText; + + public ColumnScroll categoryColumnScroll; + + public Stack categoryContainer; + + public Widget categoryCardBackground; + + public Column categoryCardContainer; + + public Widget divider; + + public Column contentContainer; + + public ValueAnimated categoryCardBackgroundAnimator; + + private static WeakReference contextRef = new WeakReference<>(null); + + public static void init(Context context) { + contextRef = new WeakReference<>(context.getApplicationContext()); + } + + private static final String LANGUAGE_SWITCH_FILE_PATH = "/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; + // .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + /* ---------- 2. 中英文映射 ---------- */ + private final Map cardTexts = new LinkedHashMap<>(); + + /* ---------- 3. 双语工具 ---------- */ + private boolean isChinese() { + return new java.io.File(LANGUAGE_SWITCH_FILE_PATH).exists(); + } + + private void updateAllCardsText() { + for (Map.Entry e : cardTexts.entrySet()) { + String target = isChinese() ? e.getValue()[0] : e.getValue()[1]; + e.getKey().setText(target); + } + } + + public ClickGUI(FloatButton floatButton) { + this.floatButton = floatButton; + this.categoryCardList = new ArrayList<>(); + addCategoryCards(); + updateAllCardsText(); // ← 新增:首次刷新 + + setWidth(MatchParent); + setHeight(MatchParent); + setAnimation(Animation.InputMethod); + setFocusable(false); + setContentView(createContentView()); + + } + + /* ---------- 固定路径常量 ---------- */ + + + /* ---------- 统一改色 ---------- */ + + + /* ---------- addCategoryCards 完成体 ---------- */ + + + private void addCategoryCards() { + final String[][] titles = { + {"战斗", "Combat"}, + {"玩家", "Player"}, + {"世界", "World"}, + {"灵体", "Sprint"}, + {"绘制", "ESP"}, + {"传送", "Teleport"}, + {"杂项", "Misc"}, + {"文件", "Document"}, + {"设置", "Settings"}, + {"关于", "About"} + }; + final ViewHelper[] contents = { + new AttackCategoryBox(), + new PlayerCategoryBox(), + new WorldCategoryBox(), + new SOULCategoryBox(), + new ESPCategoryBox(), + new TPCategoryBox(), + new MiscCategoryBox(), + new SpecialCategoryBox(), + new SettingCategoryBox(), + new aboutCategoryBox() + }; + + for (int i = 0; i < titles.length; i++) { + CategoryCard card = CategoryCard(isChinese() ? titles[i][0] : titles[i][1], contents[i]); + cardTexts.put(card, titles[i]); // 保存双语 + + categoryCardList.add(card); + } + } + + /* ---------- 6. 单语构造(保持兼容) ---------- */ + private CategoryCard CategoryCard(String text, ViewHelper content) { + return new CategoryCard() + .setText(text) + + + .setContent(content); + + + } + + private Column createContentView() { + maskContainer = new Column() + .setBackgroundColor(hexColor("#22000000")) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent)) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 点击背景区域关闭界面 (根据设置决定是否执行) + if (SettingCategoryBox.enableClickBackgroundClose) { + floatButton.closeClickGUI(); + } + } + }); + + panelContainer = new Row() + .setElevation(dip2px(12)) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setMargins(dip2pxInt(150), dip2pxInt(50), dip2pxInt(150), dip2pxInt(50))) + .setBackground( + new GradientDrawableBuilder() + .setOrientation(GradientDrawable.Orientation.LEFT_RIGHT) // 设置渐变方向 + .setColor(hexColor("#9C000000")) + .setAllRadius(dip2px(8))) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 点击面板内部不做处理 + } + }); + maskContainer.addView(panelContainer); + + panelContainer.addView(createCategoryUI()); + panelContainer.addView(createDividerUI()); + panelContainer.addView(createContentUI()); + + if (!categoryCardList.isEmpty()) { + switchContent(categoryCardList.get(0)); + } + + return maskContainer; + } + + private Column createCategoryUI() { + categoryUIContainer = new Column() + .setLayoutParams( + new LinearParams() + .setWidth(dip2pxInt(180)) + .setHeight(BaseHelper.MatchParent)); + + mixContainer = new Relative() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10)) + .setBottomMargin(dip2pxInt(10))) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + floatButton.closeClickGUI(); + } + }); + categoryUIContainer.addView(mixContainer); + + mixTitleText = new Text() + .setId(MIX_TITLE_TEXT_ID) + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.CENTER_IN_PARENT)) + .setPadding(dip2pxInt(5), 0, dip2pxInt(1), 0) + .setText("TrosCore") + .setTextSize(20f) + .setTextColor(hexColor("#FF9198E5")) + .setShadowLayer(10, 0, 0, hexColor("#FF9198E5")) + .setTypeface(Typeface.DEFAULT_BOLD); + mixContainer.addView(mixTitleText); + + mixSubTitleText = new Text() + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.END_OF, MIX_TITLE_TEXT_ID)) + .setPadding(dip2pxInt(1), 0, dip2pxInt(5), 0) + .setText("PRO") + .setTextSize(10f) + .setTextColor(hexColor("#FFD0D0E5")) + .setTypeface(Typeface.MONOSPACE) + .setShadowLayer(10, 0, 0, hexColor("#FFD0D0E5")) + .setTypeface(Typeface.DEFAULT_BOLD); + mixContainer.addView(mixSubTitleText); + + categoryColumnScroll = new ColumnScroll() + .setScrollBarEnabled(false) + .setFadingEdgeEnabled(true) + .setFadingEdgeLength(dip2pxInt(15)) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(10))); + categoryUIContainer.addView(categoryColumnScroll); + + categoryContainer = new Stack() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + categoryColumnScroll.addView(categoryContainer); + + categoryCardBackground = new Widget() + .setLayoutParams( + new StackParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(34)) + .setMargins(dip2pxInt(15), 0, dip2pxInt(15), 0)) + .setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#25D0D0D0")) + .setAllRadius(dip2px(8))); + categoryContainer.addView(categoryCardBackground); + + categoryCardContainer = new Column() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + categoryContainer.addView(categoryCardContainer); + + for (int index = 0; index < categoryCardList.size(); index++) { + addCategoryCard(categoryCardList.get(index), index); + } + + return categoryUIContainer; + } + + private void addCategoryCard(final CategoryCard categoryCard, final int index) { + if (categoryCardBackgroundAnimator == null) { + categoryCardBackgroundAnimator = new ValueAnimated() + .setDuration(200L) + .setInterpolator(new FastOutSlowInInterpolator()) + .addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(android.animation.ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + categoryCardBackground.setY(animatedValue); + } + }); + } + + categoryCard.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (contentContainer.build().indexOfChild(categoryCard.content.build()) >= 0) { + return; + } + + if (categoryCardBackgroundAnimator.build().isRunning()) { + categoryCardBackgroundAnimator.cancel(); + } + + categoryCardBackgroundAnimator.ofFloat( + categoryCardBackground.build().getY(), + dip2pxInt(34) * index).start(); + + switchContent(categoryCard); + } + }); + categoryCardContainer.addView(categoryCard); + } + + private Widget createDividerUI() { + divider = new Widget() + .setBackgroundColor(hexColor("#40D0D0D0")) + .setLayoutParams( + new LinearParams() + .setWidth(dip2pxInt(1)) + .setHeight(BaseHelper.MatchParent) + .setTopMargin(dip2pxInt(10)) + .setBottomMargin(dip2pxInt(10))); + return divider; + } + + private Column createContentUI() { + contentContainer = new Column() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setLeftMargin(dip2pxInt(15)) + .setRightMargin(dip2pxInt(15))) + .layoutTransition(); + + return contentContainer; + } + + private void switchContent(final CategoryCard categoryCard) { + contentContainer.removeAllViews(); + contentContainer.addView(categoryCard.content); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/ui/gui/ClickGUI.java.bak b/app/src/main/java/com/bytecat/algui/ui/gui/ClickGUI.java.bak new file mode 100644 index 0000000..4110bd6 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/ui/gui/ClickGUI.java.bak @@ -0,0 +1,401 @@ +package com.bytecat.algui.ui.gui; + +import android.graphics.Typeface; +import android.view.View; +import android.widget.RelativeLayout; + +import com.bytecat.algui.animation.ValueAnimated; +import com.bytecat.algui.base.BaseHelper; +import com.bytecat.algui.base.ViewHelper; +import com.bytecat.algui.component.Column; +import com.bytecat.algui.component.ColumnScroll; +import com.bytecat.algui.component.Popup; +import com.bytecat.algui.component.Relative; +import com.bytecat.algui.component.Row; +import com.bytecat.algui.component.Stack; +import com.bytecat.algui.component.Text; +import com.bytecat.algui.component.Widget; +import com.bytecat.algui.interpolator.FastOutSlowInInterpolator; +import com.bytecat.algui.layoutparams.LinearParams; +import com.bytecat.algui.layoutparams.RelativeParams; +import com.bytecat.algui.layoutparams.StackParams; +import com.bytecat.algui.ui.button.FloatButton; +import com.bytecat.algui.ui.category.aboutCategoryBox; +import com.bytecat.algui.ui.category.MiscCategoryBox; +import com.bytecat.algui.ui.category.PlayerCategoryBox; +import com.bytecat.algui.ui.category.AttackCategoryBox; +import com.bytecat.algui.ui.category.SettingCategoryBox; + + +import com.bytecat.algui.ui.category.WorldCategoryBox; +import com.bytecat.algui.ui.component.CategoryCard; +import com.bytecat.algui.util.GradientDrawableBuilder; + +import java.util.ArrayList; +import java.util.List; +import android.content.Context; +import android.graphics.Bitmap; +import com.bytecat.algui.view.BlurHelper; +import android.app.Activity; +import android.graphics.drawable.BitmapDrawable; +import android.view.Window; +import java.lang.ref.WeakReference; +import com.bytecat.algui.AlguiWindows.AlguiWin2FA; +import com.bytecat.algui.AlguiManager.AlguiCallback; +import java.util.HashMap; +import com.bytecat.algui.AlguiTools.AlguiToolNative; +import com.topjohnwu.superuser.ipc.RootService; +import android.content.Intent; +import com.bytecat.algui.AlguiHacker.AlguiRootClient; +import android.os.AsyncTask; +import com.bytecat.algui.AlguiTools.AlguiToolNetwork; +import com.bytecat.algui.AlguiManager.AlguiDocument; +import com.bytecat.algui.AlguiTools.AlguiToolAudio; +import com.bytecat.algui.AlguiManager.AlguiAssets; +import com.bytecat.algui.AlguiHacker.AlguiRootService; +import com.bytecat.algui.MainActivity; +import android.graphics.drawable.GradientDrawable; +import com.bytecat.algui.ui.category.TPCategoryBox; +import com.bytecat.algui.ui.category.SettingCategoryBox; +import java.util.Map; +import java.util.LinkedHashMap; +import com.bytecat.algui.ui.category.ESPCategoryBox; +import com.bytecat.algui.ui.category.SpecialCategoryBox; + +public class ClickGUI extends Popup { + + private Context context; + + public static final int MIX_TITLE_TEXT_ID = View.generateViewId(); + + public FloatButton floatButton; + + public List categoryCardList; + + public Column maskContainer; + + public Row panelContainer; + + public Column categoryUIContainer; + + public Relative mixContainer; + + public Text mixTitleText; + + public Text mixSubTitleText; + + public ColumnScroll categoryColumnScroll; + + public Stack categoryContainer; + + public Widget categoryCardBackground; + + public Column categoryCardContainer; + + public Widget divider; + + public Column contentContainer; + + public ValueAnimated categoryCardBackgroundAnimator; + + private static WeakReference contextRef = new WeakReference<>(null); + + public static void init(Context context) { + contextRef = new WeakReference<>(context.getApplicationContext()); + } + + private static final String LANGUAGE_SWITCH_FILE_PATH = "/sdcard/Android/data/com.vortex.celestial/files/switch.lang"; + // .setLanguageSwitchFilePath("/sdcard/Android/data/com.vortex.celestial/files/switch.lang"); + + /* ---------- 2. 中英文映射 ---------- */ + private final Map cardTexts = new LinkedHashMap<>(); + + /* ---------- 3. 双语工具 ---------- */ + private boolean isChinese() { + return new java.io.File(LANGUAGE_SWITCH_FILE_PATH).exists(); + } + + private void updateAllCardsText() { + for (Map.Entry e : cardTexts.entrySet()) { + String target = isChinese() ? e.getValue()[0] : e.getValue()[1]; + e.getKey().setText(target); + } + } + + public ClickGUI(FloatButton floatButton) { + this.floatButton = floatButton; + this.categoryCardList = new ArrayList<>(); + addCategoryCards(); + updateAllCardsText(); // ← 新增:首次刷新 + + setWidth(MatchParent); + setHeight(MatchParent); + setAnimation(Animation.InputMethod); + setFocusable(false); + setContentView(createContentView()); + + } + + /* ---------- 固定路径常量 ---------- */ + + + /* ---------- 统一改色 ---------- */ + + + /* ---------- addCategoryCards 完成体 ---------- */ + + + private void addCategoryCards() { + final String[][] titles = { + {"战斗", "Combat"}, + {"玩家", "Player"}, + {"世界", "World"}, + {"灵体", "Sprint"}, + {"绘制", "ESP"}, + {"传送", "Teleport"}, + {"杂项", "Misc"}, + {"文件", "Document"}, + {"设置", "Settings"}, + {"关于", "About"} + }; + final ViewHelper[] contents = { + new AttackCategoryBox(), + new PlayerCategoryBox(), + new WorldCategoryBox(), + new ESPCategoryBox(), + new TPCategoryBox(), + new MiscCategoryBox(), + new SpecialCategoryBox(), + new SettingCategoryBox(), + new aboutCategoryBox() + }; + + for (int i = 0; i < titles.length; i++) { + CategoryCard card = CategoryCard(isChinese() ? titles[i][0] : titles[i][1], contents[i]); + cardTexts.put(card, titles[i]); // 保存双语 + + categoryCardList.add(card); + } + } + + /* ---------- 6. 单语构造(保持兼容) ---------- */ + private CategoryCard CategoryCard(String text, ViewHelper content) { + return new CategoryCard() + .setText(text) + + + .setContent(content); + + + } + + private Column createContentView() { + maskContainer = new Column() + .setBackgroundColor(hexColor("#22000000")) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent)) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 点击背景区域关闭界面 (根据设置决定是否执行) + if (SettingCategoryBox.enableClickBackgroundClose) { + floatButton.closeClickGUI(); + } + } + }); + + panelContainer = new Row() + .setElevation(dip2px(12)) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setMargins(dip2pxInt(150), dip2pxInt(50), dip2pxInt(150), dip2pxInt(50))) + .setBackground( + new GradientDrawableBuilder() + .setOrientation(GradientDrawable.Orientation.LEFT_RIGHT) // 设置渐变方向 + .setColor(hexColor("#9C000000")) + .setAllRadius(dip2px(8))) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 点击面板内部不做处理 + } + }); + maskContainer.addView(panelContainer); + + panelContainer.addView(createCategoryUI()); + panelContainer.addView(createDividerUI()); + panelContainer.addView(createContentUI()); + + if (!categoryCardList.isEmpty()) { + switchContent(categoryCardList.get(0)); + } + + return maskContainer; + } + + private Column createCategoryUI() { + categoryUIContainer = new Column() + .setLayoutParams( + new LinearParams() + .setWidth(dip2pxInt(180)) + .setHeight(BaseHelper.MatchParent)); + + mixContainer = new Relative() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent) + .setTopMargin(dip2pxInt(10)) + .setBottomMargin(dip2pxInt(10))) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + floatButton.closeClickGUI(); + } + }); + categoryUIContainer.addView(mixContainer); + + mixTitleText = new Text() + .setId(MIX_TITLE_TEXT_ID) + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.CENTER_IN_PARENT)) + .setPadding(dip2pxInt(5), 0, dip2pxInt(1), 0) + .setText("TrosCore") + .setTextSize(20f) + .setTextColor(hexColor("#FF9198E5")) + .setShadowLayer(10, 0, 0, hexColor("#FF9198E5")) + .setTypeface(Typeface.DEFAULT_BOLD); + mixContainer.addView(mixTitleText); + + mixSubTitleText = new Text() + .setLayoutParams( + new RelativeParams() + .setWidth(BaseHelper.WrapContent) + .setHeight(BaseHelper.WrapContent) + .addRule(RelativeLayout.END_OF, MIX_TITLE_TEXT_ID)) + .setPadding(dip2pxInt(1), 0, dip2pxInt(5), 0) + .setText("PRO") + .setTextSize(10f) + .setTextColor(hexColor("#FFD0D0E5")) + .setTypeface(Typeface.MONOSPACE) + .setShadowLayer(10, 0, 0, hexColor("#FFD0D0E5")) + .setTypeface(Typeface.DEFAULT_BOLD); + mixContainer.addView(mixSubTitleText); + + categoryColumnScroll = new ColumnScroll() + .setScrollBarEnabled(false) + .setFadingEdgeEnabled(true) + .setFadingEdgeLength(dip2pxInt(15)) + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setBottomMargin(dip2pxInt(10))); + categoryUIContainer.addView(categoryColumnScroll); + + categoryContainer = new Stack() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + categoryColumnScroll.addView(categoryContainer); + + categoryCardBackground = new Widget() + .setLayoutParams( + new StackParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(dip2pxInt(34)) + .setMargins(dip2pxInt(15), 0, dip2pxInt(15), 0)) + .setBackground( + new GradientDrawableBuilder() + .setColor(hexColor("#25D0D0D0")) + .setAllRadius(dip2px(8))); + categoryContainer.addView(categoryCardBackground); + + categoryCardContainer = new Column() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.WrapContent)); + categoryContainer.addView(categoryCardContainer); + + for (int index = 0; index < categoryCardList.size(); index++) { + addCategoryCard(categoryCardList.get(index), index); + } + + return categoryUIContainer; + } + + private void addCategoryCard(final CategoryCard categoryCard, final int index) { + if (categoryCardBackgroundAnimator == null) { + categoryCardBackgroundAnimator = new ValueAnimated() + .setDuration(200L) + .setInterpolator(new FastOutSlowInInterpolator()) + .addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(android.animation.ValueAnimator animation) { + float animatedValue = (float) animation.getAnimatedValue(); + categoryCardBackground.setY(animatedValue); + } + }); + } + + categoryCard.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (contentContainer.build().indexOfChild(categoryCard.content.build()) >= 0) { + return; + } + + if (categoryCardBackgroundAnimator.build().isRunning()) { + categoryCardBackgroundAnimator.cancel(); + } + + categoryCardBackgroundAnimator.ofFloat( + categoryCardBackground.build().getY(), + dip2pxInt(34) * index).start(); + + switchContent(categoryCard); + } + }); + categoryCardContainer.addView(categoryCard); + } + + private Widget createDividerUI() { + divider = new Widget() + .setBackgroundColor(hexColor("#40D0D0D0")) + .setLayoutParams( + new LinearParams() + .setWidth(dip2pxInt(1)) + .setHeight(BaseHelper.MatchParent) + .setTopMargin(dip2pxInt(10)) + .setBottomMargin(dip2pxInt(10))); + return divider; + } + + private Column createContentUI() { + contentContainer = new Column() + .setLayoutParams( + new LinearParams() + .setWidth(BaseHelper.MatchParent) + .setHeight(BaseHelper.MatchParent) + .setLeftMargin(dip2pxInt(15)) + .setRightMargin(dip2pxInt(15))) + .layoutTransition(); + + return contentContainer; + } + + private void switchContent(final CategoryCard categoryCard) { + contentContainer.removeAllViews(); + contentContainer.addView(categoryCard.content); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/util/GradientDrawableBuilder.java b/app/src/main/java/com/bytecat/algui/util/GradientDrawableBuilder.java new file mode 100644 index 0000000..a4e2806 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/util/GradientDrawableBuilder.java @@ -0,0 +1,67 @@ +package com.bytecat.algui.util; + +import android.graphics.drawable.GradientDrawable; + +import com.bytecat.algui.base.BaseHelper; + +public class GradientDrawableBuilder extends BaseHelper { + + private final GradientDrawable gradientDrawable; + + public GradientDrawableBuilder() { + gradientDrawable = new GradientDrawable(); + } + + public GradientDrawableBuilder setOrientation(GradientDrawable.Orientation orientation) { + gradientDrawable.setOrientation(orientation); + return this; + } + + public GradientDrawableBuilder setGradientType(int type) { + gradientDrawable.setGradientType(type); + return this; + } + + public GradientDrawableBuilder setShape(int shape) { + gradientDrawable.setShape(shape); + return this; + } + + public GradientDrawableBuilder setColor(int color) { + gradientDrawable.setColor(color); + return this; + } + + public GradientDrawableBuilder setStroke(int width, int color) { + gradientDrawable.setStroke(width, color); + return this; + } + + public GradientDrawableBuilder setColors(int... colors) { + gradientDrawable.setColors(colors); + return this; + } + + public GradientDrawableBuilder setRadius(float... radius) { + if (radius.length != 4 && radius.length != 8) { + throw new IllegalArgumentException("radius array length must equals 4 or 8"); + } + + if (radius.length == 4) { + gradientDrawable.setCornerRadii(new float[]{radius[0], radius[0], radius[1], radius[1], radius[2], radius[2], radius[3], radius[3]}); + } else { + gradientDrawable.setCornerRadii(radius); + } + return this; + } + + public GradientDrawableBuilder setAllRadius(float radius) { + setRadius(radius, radius, radius, radius); + return this; + } + + public GradientDrawable build() { + return gradientDrawable; + } + +} diff --git a/app/src/main/java/com/bytecat/algui/util/SyncUtil.java b/app/src/main/java/com/bytecat/algui/util/SyncUtil.java new file mode 100644 index 0000000..52aef62 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/util/SyncUtil.java @@ -0,0 +1,46 @@ +package com.bytecat.algui.util; + +import com.bytecat.algui.callback.SwitchCallback; +import com.bytecat.algui.ui.button.SwitchShortcutButton; +import com.bytecat.algui.ui.component.Switch; +import com.bytecat.algui.ui.component.SwitchContent; +import com.bytecat.algui.ui.component.SwitchContentCard; + +public final class SyncUtil { + + private SyncUtil() { + } + + public static void sync(SwitchContentCard switchContentCard, SwitchShortcutButton shortcutButton, SwitchCallback switchCallback) { + sync(switchContentCard.switchContent, shortcutButton, switchCallback); + } + + public static void sync(SwitchContent switchContent, SwitchShortcutButton shortcutButton, SwitchCallback switchCallback) { + sync(switchContent.mSwitch, shortcutButton, switchCallback); + } + + public static void sync(final Switch pSwitch, final SwitchShortcutButton shortcutButton, final SwitchCallback callback) { + pSwitch.setSwitchCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (callback.onChecked(newState)) { + shortcutButton.setChecked(newState); + return true; + } + return false; + } + }); + + shortcutButton.setSwicthCallback(new SwitchCallback() { + @Override + public boolean onChecked(boolean newState) { + if (callback.onChecked(newState)) { + pSwitch.setChecked(newState); + return true; + } + return false; + } + }); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/view/AndroidStockBlurImpl.java b/app/src/main/java/com/bytecat/algui/view/AndroidStockBlurImpl.java new file mode 100644 index 0000000..dce52ba --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/AndroidStockBlurImpl.java @@ -0,0 +1,66 @@ +package com.bytecat.algui.view; + +import android.content.Context; +import android.graphics.Bitmap; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RenderScript; +import android.renderscript.ScriptIntrinsicBlur; + +/** + * @noinspection ALL + */ +public class AndroidStockBlurImpl implements BlurImpl { + private RenderScript mRenderScript; + private ScriptIntrinsicBlur mBlurScript; + private Allocation mBlurInput, mBlurOutput; + + @Override + public boolean prepare(Context context, Bitmap buffer, float radius) { + if (mRenderScript == null) { + try { + mRenderScript = RenderScript.create(context); + mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript)); + } catch (android.renderscript.RSRuntimeException e) { + release(); + return false; + } + } + mBlurScript.setRadius(radius); + + mBlurInput = Allocation.createFromBitmap(mRenderScript, buffer, + Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); + mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType()); + + return true; + } + + @Override + public void release() { + if (mBlurInput != null) { + mBlurInput.destroy(); + mBlurInput = null; + } + if (mBlurOutput != null) { + mBlurOutput.destroy(); + mBlurOutput = null; + } + if (mBlurScript != null) { + mBlurScript.destroy(); + mBlurScript = null; + } + if (mRenderScript != null) { + mRenderScript.destroy(); + mRenderScript = null; + } + } + + @Override + public void blur(Bitmap input, Bitmap output) { + mBlurInput.copyFrom(input); + mBlurScript.setInput(mBlurInput); + mBlurScript.forEach(mBlurOutput); + mBlurOutput.copyTo(output); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/view/BlurHelper.java b/app/src/main/java/com/bytecat/algui/view/BlurHelper.java new file mode 100644 index 0000000..5f69f04 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/BlurHelper.java @@ -0,0 +1,32 @@ +package com.bytecat.algui.view; + +import android.content.Context; +import android.graphics.Bitmap; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RenderScript; +import android.renderscript.ScriptIntrinsicBlur; + +public class BlurHelper { + public static Bitmap blurBitmap(Context context, Bitmap sourceBitmap, float blurRadius) { + if (sourceBitmap == null) { + return null; + } + + Bitmap blurredBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight(), Bitmap.Config.ARGB_8888); + + RenderScript renderScript = RenderScript.create(context); + Allocation allIn = Allocation.createFromBitmap(renderScript, sourceBitmap); + Allocation allOut = Allocation.createFromBitmap(renderScript, blurredBitmap); + + ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript)); + script.setRadius(blurRadius); // 设置模糊半径,范围 [0, 25] + script.setInput(allIn); + script.forEach(allOut); + + allOut.copyTo(blurredBitmap); + renderScript.destroy(); + + return blurredBitmap; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/view/BlurImpl.java b/app/src/main/java/com/bytecat/algui/view/BlurImpl.java new file mode 100644 index 0000000..d2190f7 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/BlurImpl.java @@ -0,0 +1,14 @@ +package com.bytecat.algui.view; + +import android.content.Context; +import android.graphics.Bitmap; + +interface BlurImpl { + + boolean prepare(Context context, Bitmap buffer, float radius); + + void release(); + + void blur(Bitmap input, Bitmap output); + +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/view/CardView.java b/app/src/main/java/com/bytecat/algui/view/CardView.java new file mode 100644 index 0000000..ff0e7c4 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/CardView.java @@ -0,0 +1,460 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytecat.algui.view; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; + +/** + * A FrameLayout with a rounded corner background and shadow. + *

+ * CardView uses elevation property on Lollipop for shadows and falls back to a + * custom emulated shadow implementation on older platforms. + *

+ * Due to expensive nature of rounded corner clipping, on platforms before Lollipop, CardView does + * not clip its children that intersect with rounded corners. Instead, it adds padding to avoid such + * intersection (See {@link #setPreventCornerOverlap(boolean)} to change this behavior). + *

+ * Before Lollipop, CardView adds padding to its content and draws shadows to that area. This + * padding amount is equal to maxCardElevation + (1 - cos45) * cornerRadius on the + * sides and maxCardElevation * 1.5 + (1 - cos45) * cornerRadius on top and bottom. + *

+ * Since padding is used to offset content for shadows, you cannot set padding on CardView. + * Instead, you can use content padding attributes in XML or + * {@link #setContentPadding(int, int, int, int)} in code to set the padding between the edges of + * the CardView and children of CardView. + *

+ * Note that, if you specify exact dimensions for the CardView, because of the shadows, its content + * area will be different between platforms before Lollipop and after Lollipop. By using api version + * specific resource values, you can avoid these changes. Alternatively, If you want CardView to add + * inner padding on platforms Lollipop and after as well, you can call + * {@link #setUseCompatPadding(boolean)} and pass true. + *

+ * To change CardView's elevation in a backward compatible way, use + * {@link #setCardElevation(float)}. CardView will use elevation API on Lollipop and before + * Lollipop, it will change the shadow size. To avoid moving the View while shadow size is changing, + * shadow size is clamped by {@link #getMaxCardElevation()}. If you want to change elevation + * dynamically, you should call {@link #setMaxCardElevation(float)} when CardView is initialized. + *

+ * {@link androidx.cardview.R.attr#cardBackgroundColor} + * {@link androidx.cardview.R.attr#cardCornerRadius} + * {@link androidx.cardview.R.attr#cardElevation} + * {@link androidx.cardview.R.attr#cardMaxElevation} + * {@link androidx.cardview.R.attr#cardUseCompatPadding} + * {@link androidx.cardview.R.attr#cardPreventCornerOverlap} + * {@link androidx.cardview.R.attr#contentPadding} + * {@link androidx.cardview.R.attr#contentPaddingLeft} + * {@link androidx.cardview.R.attr#contentPaddingTop} + * {@link androidx.cardview.R.attr#contentPaddingRight} + * {@link androidx.cardview.R.attr#contentPaddingBottom} + */ +public class CardView extends FrameLayout { + + private static final CardViewImpl IMPL; + + static { + if (Build.VERSION.SDK_INT >= 21) { + IMPL = new CardViewApi21Impl(); + } else { + IMPL = new CardViewBaseImpl(); + } + IMPL.initStatic(); + } + + private boolean mCompatPadding; + + private boolean mPreventCornerOverlap; + + /** + * CardView requires to have a particular minimum size to draw shadows before API 21. If + * developer also sets min width/height, they might be overridden. + *

+ * CardView works around this issue by recording user given parameters and using an internal + * method to set them. + */ + int mUserSetMinWidth, mUserSetMinHeight; + + final Rect mContentPadding = new Rect(); + + final Rect mShadowBounds = new Rect(); + + public CardView(Context context) { + this(context, null); + } + + public CardView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CardView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + ColorStateList backgroundColor; + + // If the theme colorBackground is light, use our own light color, otherwise dark + final float[] hsv = new float[3]; + Color.colorToHSV(0, hsv); + + backgroundColor = ColorStateList.valueOf(hsv[2] > 0.5f ? Color.parseColor("#FFFFFFFF") + : Color.parseColor("#FF424242")); + + float radius = 0; + float elevation = 0; + float maxElevation = 0; + mCompatPadding = false; + mPreventCornerOverlap = true; + mContentPadding.left = 0; + mContentPadding.top = 0; + mContentPadding.right = 0; + mContentPadding.bottom = 0; + mUserSetMinWidth = 0; + mUserSetMinHeight = 0; + + IMPL.initialize(mCardViewDelegate, context, backgroundColor, radius, + elevation, maxElevation); + } + + @Override + public void setPadding(int left, int top, int right, int bottom) { + // NO OP + } + + @Override + public void setPaddingRelative(int start, int top, int end, int bottom) { + // NO OP + } + + /** + * Returns whether CardView will add inner padding on platforms Lollipop and after. + * + * @return true if CardView adds inner padding on platforms Lollipop and after to + * have same dimensions with platforms before Lollipop. + */ + public boolean getUseCompatPadding() { + return mCompatPadding; + } + + /** + * CardView adds additional padding to draw shadows on platforms before Lollipop. + *

+ * This may cause Cards to have different sizes between Lollipop and before Lollipop. If you + * need to align CardView with other Views, you may need api version specific dimension + * resources to account for the changes. + * As an alternative, you can set this flag to true and CardView will add the same + * padding values on platforms Lollipop and after. + *

+ * Since setting this flag to true adds unnecessary gaps in the UI, default value is + * false. + * + * @param useCompatPadding true> if CardView should add padding for the shadows on + * platforms Lollipop and above. + * {@link androidx.cardview.R.attr#cardUseCompatPadding} + */ + public void setUseCompatPadding(boolean useCompatPadding) { + if (mCompatPadding != useCompatPadding) { + mCompatPadding = useCompatPadding; + IMPL.onCompatPaddingChanged(mCardViewDelegate); + } + } + + /** + * Sets the padding between the Card's edges and the children of CardView. + *

+ * Depending on platform version or {@link #getUseCompatPadding()} settings, CardView may + * update these values before calling {@link android.view.View#setPadding(int, int, int, int)}. + * + * @param left The left padding in pixels + * @param top The top padding in pixels + * @param right The right padding in pixels + * @param bottom The bottom padding in pixels + * {@link androidx.cardview.R.attr#contentPadding} + * {@link androidx.cardview.R.attr#contentPaddingLeft} + * {@link androidx.cardview.R.attr#contentPaddingTop} + * {@link androidx.cardview.R.attr#contentPaddingRight} + * {@link androidx.cardview.R.attr#contentPaddingBottom} + */ + public void setContentPadding(int left, int top, int right, int bottom) { + mContentPadding.set(left, top, right, bottom); + IMPL.updatePadding(mCardViewDelegate); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (!(IMPL instanceof CardViewApi21Impl)) { + final int widthMode = MeasureSpec.getMode(widthMeasureSpec); + switch (widthMode) { + case MeasureSpec.EXACTLY: + case MeasureSpec.AT_MOST: + final int minWidth = (int) Math.ceil(IMPL.getMinWidth(mCardViewDelegate)); + widthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minWidth, + MeasureSpec.getSize(widthMeasureSpec)), widthMode); + break; + case MeasureSpec.UNSPECIFIED: + // Do nothing + break; + } + + final int heightMode = MeasureSpec.getMode(heightMeasureSpec); + switch (heightMode) { + case MeasureSpec.EXACTLY: + case MeasureSpec.AT_MOST: + final int minHeight = (int) Math.ceil(IMPL.getMinHeight(mCardViewDelegate)); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minHeight, + MeasureSpec.getSize(heightMeasureSpec)), heightMode); + break; + case MeasureSpec.UNSPECIFIED: + // Do nothing + break; + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + public void setMinimumWidth(int minWidth) { + mUserSetMinWidth = minWidth; + super.setMinimumWidth(minWidth); + } + + @Override + public void setMinimumHeight(int minHeight) { + mUserSetMinHeight = minHeight; + super.setMinimumHeight(minHeight); + } + + /** + * Updates the background color of the CardView + * + * @param color The new color to set for the card background + * {@link androidx.cardview.R.attr#cardBackgroundColor} + */ + public void setCardBackgroundColor(int color) { + IMPL.setBackgroundColor(mCardViewDelegate, ColorStateList.valueOf(color)); + } + + /** + * Updates the background ColorStateList of the CardView + * + * @param color The new ColorStateList to set for the card background + * {@link androidx.cardview.R.attr#cardBackgroundColor} + */ + public void setCardBackgroundColor(ColorStateList color) { + IMPL.setBackgroundColor(mCardViewDelegate, color); + } + + /** + * Returns the background color state list of the CardView. + * + * @return The background color state list of the CardView. + */ + public ColorStateList getCardBackgroundColor() { + return IMPL.getBackgroundColor(mCardViewDelegate); + } + + /** + * Returns the inner padding after the Card's left edge + * + * @return the inner padding after the Card's left edge + */ + public int getContentPaddingLeft() { + return mContentPadding.left; + } + + /** + * Returns the inner padding before the Card's right edge + * + * @return the inner padding before the Card's right edge + */ + public int getContentPaddingRight() { + return mContentPadding.right; + } + + /** + * Returns the inner padding after the Card's top edge + * + * @return the inner padding after the Card's top edge + */ + public int getContentPaddingTop() { + return mContentPadding.top; + } + + /** + * Returns the inner padding before the Card's bottom edge + * + * @return the inner padding before the Card's bottom edge + */ + public int getContentPaddingBottom() { + return mContentPadding.bottom; + } + + /** + * Updates the corner radius of the CardView. + * + * @param radius The radius in pixels of the corners of the rectangle shape + * {@link androidx.cardview.R.attr#cardCornerRadius} + * @see #setRadius(float) + */ + public void setRadius(float radius) { + IMPL.setRadius(mCardViewDelegate, radius); + } + + /** + * Returns the corner radius of the CardView. + * + * @return Corner radius of the CardView + * @see #getRadius() + */ + public float getRadius() { + return IMPL.getRadius(mCardViewDelegate); + } + + /** + * Updates the backward compatible elevation of the CardView. + * + * @param elevation The backward compatible elevation in pixels. + * {@link androidx.cardview.R.attr#cardElevation} + * @see #getCardElevation() + * @see #setMaxCardElevation(float) + */ + public void setCardElevation(float elevation) { + IMPL.setElevation(mCardViewDelegate, elevation); + } + + /** + * Returns the backward compatible elevation of the CardView. + * + * @return Elevation of the CardView + * @see #setCardElevation(float) + * @see #getMaxCardElevation() + */ + public float getCardElevation() { + return IMPL.getElevation(mCardViewDelegate); + } + + /** + * Updates the backward compatible maximum elevation of the CardView. + *

+ * Calling this method has no effect if device OS version is Lollipop or newer and + * {@link #getUseCompatPadding()} is false. + * + * @param maxElevation The backward compatible maximum elevation in pixels. + * {@link androidx.cardview.R.attr#cardMaxElevation} + * @see #setCardElevation(float) + * @see #getMaxCardElevation() + */ + public void setMaxCardElevation(float maxElevation) { + IMPL.setMaxElevation(mCardViewDelegate, maxElevation); + } + + /** + * Returns the backward compatible maximum elevation of the CardView. + * + * @return Maximum elevation of the CardView + * @see #setMaxCardElevation(float) + * @see #getCardElevation() + */ + public float getMaxCardElevation() { + return IMPL.getMaxElevation(mCardViewDelegate); + } + + /** + * Returns whether CardView should add extra padding to content to avoid overlaps with rounded + * corners on pre-Lollipop platforms. + * + * @return True if CardView prevents overlaps with rounded corners on platforms before Lollipop. + * Default value is true. + */ + public boolean getPreventCornerOverlap() { + return mPreventCornerOverlap; + } + + /** + * On pre-Lollipop platforms, CardView does not clip the bounds of the Card for the rounded + * corners. Instead, it adds padding to content so that it won't overlap with the rounded + * corners. You can disable this behavior by setting this field to false. + *

+ * Setting this value on Lollipop and above does not have any effect unless you have enabled + * compatibility padding. + * + * @param preventCornerOverlap Whether CardView should add extra padding to content to avoid + * overlaps with the CardView corners. + * {@link androidx.cardview.R.attr#cardPreventCornerOverlap} + * @see #setUseCompatPadding(boolean) + */ + public void setPreventCornerOverlap(boolean preventCornerOverlap) { + if (preventCornerOverlap != mPreventCornerOverlap) { + mPreventCornerOverlap = preventCornerOverlap; + IMPL.onPreventCornerOverlapChanged(mCardViewDelegate); + } + } + + private final CardViewDelegate mCardViewDelegate = new CardViewDelegate() { + private Drawable mCardBackground; + + @Override + public void setCardBackground(Drawable drawable) { + mCardBackground = drawable; + setBackgroundDrawable(drawable); + } + + @Override + public boolean getUseCompatPadding() { + return CardView.this.getUseCompatPadding(); + } + + @Override + public boolean getPreventCornerOverlap() { + return CardView.this.getPreventCornerOverlap(); + } + + @Override + public void setShadowPadding(int left, int top, int right, int bottom) { + mShadowBounds.set(left, top, right, bottom); + CardView.super.setPadding(left + mContentPadding.left, top + mContentPadding.top, + right + mContentPadding.right, bottom + mContentPadding.bottom); + } + + @Override + public void setMinWidthHeightInternal(int width, int height) { + if (width > mUserSetMinWidth) { + CardView.super.setMinimumWidth(width); + } + if (height > mUserSetMinHeight) { + CardView.super.setMinimumHeight(height); + } + } + + @Override + public Drawable getCardBackground() { + return mCardBackground; + } + + @Override + public View getCardView() { + return CardView.this; + } + }; +} diff --git a/app/src/main/java/com/bytecat/algui/view/CardViewApi21Impl.java b/app/src/main/java/com/bytecat/algui/view/CardViewApi21Impl.java new file mode 100644 index 0000000..aadf5a9 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/CardViewApi21Impl.java @@ -0,0 +1,120 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytecat.algui.view; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.view.View; + +class CardViewApi21Impl implements CardViewImpl { + + @Override + public void initialize(CardViewDelegate cardView, Context context, + ColorStateList backgroundColor, float radius, float elevation, float maxElevation) { + final RoundRectDrawable background = new RoundRectDrawable(backgroundColor, radius); + cardView.setCardBackground(background); + + View view = cardView.getCardView(); + view.setClipToOutline(true); + view.setElevation(elevation); + setMaxElevation(cardView, maxElevation); + } + + @Override + public void setRadius(CardViewDelegate cardView, float radius) { + getCardBackground(cardView).setRadius(radius); + } + + @Override + public void initStatic() { + } + + @Override + public void setMaxElevation(CardViewDelegate cardView, float maxElevation) { + getCardBackground(cardView).setPadding(maxElevation, + cardView.getUseCompatPadding(), cardView.getPreventCornerOverlap()); + updatePadding(cardView); + } + + @Override + public float getMaxElevation(CardViewDelegate cardView) { + return getCardBackground(cardView).getPadding(); + } + + @Override + public float getMinWidth(CardViewDelegate cardView) { + return getRadius(cardView) * 2; + } + + @Override + public float getMinHeight(CardViewDelegate cardView) { + return getRadius(cardView) * 2; + } + + @Override + public float getRadius(CardViewDelegate cardView) { + return getCardBackground(cardView).getRadius(); + } + + @Override + public void setElevation(CardViewDelegate cardView, float elevation) { + cardView.getCardView().setElevation(elevation); + } + + @Override + public float getElevation(CardViewDelegate cardView) { + return cardView.getCardView().getElevation(); + } + + @Override + public void updatePadding(CardViewDelegate cardView) { + if (!cardView.getUseCompatPadding()) { + cardView.setShadowPadding(0, 0, 0, 0); + return; + } + float elevation = getMaxElevation(cardView); + final float radius = getRadius(cardView); + int hPadding = (int) Math.ceil(RoundRectDrawableWithShadow + .calculateHorizontalPadding(elevation, radius, cardView.getPreventCornerOverlap())); + int vPadding = (int) Math.ceil(RoundRectDrawableWithShadow + .calculateVerticalPadding(elevation, radius, cardView.getPreventCornerOverlap())); + cardView.setShadowPadding(hPadding, vPadding, hPadding, vPadding); + } + + @Override + public void onCompatPaddingChanged(CardViewDelegate cardView) { + setMaxElevation(cardView, getMaxElevation(cardView)); + } + + @Override + public void onPreventCornerOverlapChanged(CardViewDelegate cardView) { + setMaxElevation(cardView, getMaxElevation(cardView)); + } + + @Override + public void setBackgroundColor(CardViewDelegate cardView, ColorStateList color) { + getCardBackground(cardView).setColor(color); + } + + @Override + public ColorStateList getBackgroundColor(CardViewDelegate cardView) { + return getCardBackground(cardView).getColor(); + } + + private RoundRectDrawable getCardBackground(CardViewDelegate cardView) { + return ((RoundRectDrawable) cardView.getCardBackground()); + } +} diff --git a/app/src/main/java/com/bytecat/algui/view/CardViewBaseImpl.java b/app/src/main/java/com/bytecat/algui/view/CardViewBaseImpl.java new file mode 100644 index 0000000..7f6d0cd --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/CardViewBaseImpl.java @@ -0,0 +1,132 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytecat.algui.view; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; + +class CardViewBaseImpl implements CardViewImpl { + + @Override + public void initStatic() { + RoundRectDrawableWithShadow.sRoundRectHelper = new RoundRectDrawableWithShadow.RoundRectHelper() { + + @Override + public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, Paint paint) { + canvas.drawRoundRect(bounds, cornerRadius, cornerRadius, paint); + } + + }; + } + + @Override + public void initialize(CardViewDelegate cardView, Context context, + ColorStateList backgroundColor, float radius, float elevation, float maxElevation) { + RoundRectDrawableWithShadow background = createBackground(context, backgroundColor, radius, + elevation, maxElevation); + background.setAddPaddingForCorners(cardView.getPreventCornerOverlap()); + cardView.setCardBackground(background); + updatePadding(cardView); + } + + private RoundRectDrawableWithShadow createBackground(Context context, + ColorStateList backgroundColor, float radius, float elevation, + float maxElevation) { + return new RoundRectDrawableWithShadow(context.getResources(), backgroundColor, radius, + elevation, maxElevation); + } + + @Override + public void updatePadding(CardViewDelegate cardView) { + Rect shadowPadding = new Rect(); + getShadowBackground(cardView).getMaxShadowAndCornerPadding(shadowPadding); + cardView.setMinWidthHeightInternal((int) Math.ceil(getMinWidth(cardView)), + (int) Math.ceil(getMinHeight(cardView))); + cardView.setShadowPadding(shadowPadding.left, shadowPadding.top, + shadowPadding.right, shadowPadding.bottom); + } + + @Override + public void onCompatPaddingChanged(CardViewDelegate cardView) { + // NO OP + } + + @Override + public void onPreventCornerOverlapChanged(CardViewDelegate cardView) { + getShadowBackground(cardView).setAddPaddingForCorners(cardView.getPreventCornerOverlap()); + updatePadding(cardView); + } + + @Override + public void setBackgroundColor(CardViewDelegate cardView, ColorStateList color) { + getShadowBackground(cardView).setColor(color); + } + + @Override + public ColorStateList getBackgroundColor(CardViewDelegate cardView) { + return getShadowBackground(cardView).getColor(); + } + + @Override + public void setRadius(CardViewDelegate cardView, float radius) { + getShadowBackground(cardView).setCornerRadius(radius); + updatePadding(cardView); + } + + @Override + public float getRadius(CardViewDelegate cardView) { + return getShadowBackground(cardView).getCornerRadius(); + } + + @Override + public void setElevation(CardViewDelegate cardView, float elevation) { + getShadowBackground(cardView).setShadowSize(elevation); + } + + @Override + public float getElevation(CardViewDelegate cardView) { + return getShadowBackground(cardView).getShadowSize(); + } + + @Override + public void setMaxElevation(CardViewDelegate cardView, float maxElevation) { + getShadowBackground(cardView).setMaxShadowSize(maxElevation); + updatePadding(cardView); + } + + @Override + public float getMaxElevation(CardViewDelegate cardView) { + return getShadowBackground(cardView).getMaxShadowSize(); + } + + @Override + public float getMinWidth(CardViewDelegate cardView) { + return getShadowBackground(cardView).getMinWidth(); + } + + @Override + public float getMinHeight(CardViewDelegate cardView) { + return getShadowBackground(cardView).getMinHeight(); + } + + private RoundRectDrawableWithShadow getShadowBackground(CardViewDelegate cardView) { + return ((RoundRectDrawableWithShadow) cardView.getCardBackground()); + } +} diff --git a/app/src/main/java/com/bytecat/algui/view/CardViewDelegate.java b/app/src/main/java/com/bytecat/algui/view/CardViewDelegate.java new file mode 100644 index 0000000..254c0c6 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/CardViewDelegate.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytecat.algui.view; + +import android.graphics.drawable.Drawable; +import android.view.View; + +/** + * Interface provided by CardView to implementations. + *

+ * Necessary to resolve circular dependency between base CardView and platform implementations. + */ +interface CardViewDelegate { + void setCardBackground(Drawable drawable); + + Drawable getCardBackground(); + + boolean getUseCompatPadding(); + + boolean getPreventCornerOverlap(); + + void setShadowPadding(int left, int top, int right, int bottom); + + void setMinWidthHeightInternal(int width, int height); + + View getCardView(); +} diff --git a/app/src/main/java/com/bytecat/algui/view/CardViewImpl.java b/app/src/main/java/com/bytecat/algui/view/CardViewImpl.java new file mode 100644 index 0000000..3ba98de --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/CardViewImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytecat.algui.view; + +import android.content.Context; +import android.content.res.ColorStateList; + +/** + * Interface for platform specific CardView implementations. + */ +interface CardViewImpl { + void initialize(CardViewDelegate cardView, Context context, ColorStateList backgroundColor, + float radius, float elevation, float maxElevation); + + void setRadius(CardViewDelegate cardView, float radius); + + float getRadius(CardViewDelegate cardView); + + void setElevation(CardViewDelegate cardView, float elevation); + + float getElevation(CardViewDelegate cardView); + + void initStatic(); + + void setMaxElevation(CardViewDelegate cardView, float maxElevation); + + float getMaxElevation(CardViewDelegate cardView); + + float getMinWidth(CardViewDelegate cardView); + + float getMinHeight(CardViewDelegate cardView); + + void updatePadding(CardViewDelegate cardView); + + void onCompatPaddingChanged(CardViewDelegate cardView); + + void onPreventCornerOverlapChanged(CardViewDelegate cardView); + + void setBackgroundColor(CardViewDelegate cardView, ColorStateList color); + + ColorStateList getBackgroundColor(CardViewDelegate cardView); +} diff --git a/app/src/main/java/com/bytecat/algui/view/DrawableView.java b/app/src/main/java/com/bytecat/algui/view/DrawableView.java new file mode 100644 index 0000000..6abfae8 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/DrawableView.java @@ -0,0 +1,38 @@ +package com.bytecat.algui.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.view.View; + +import com.bytecat.algui.callback.DrawCallback; + +import java.util.ArrayList; +import java.util.List; + +public class DrawableView extends View { + + private final List callbacks = new ArrayList<>(); + + public DrawableView(Context context) { + super(context); + } + + @Override + public void draw(Canvas canvas) { + for (DrawCallback callback : callbacks) { + callback.onDrawView(canvas); + } + super.draw(canvas); + } + + public void addDrawCallback(DrawCallback callback) { + callbacks.add(callback); + invalidate(); + } + + public void removeDrawCallback(DrawCallback callback) { + callbacks.remove(callback); + invalidate(); + } + +} diff --git a/app/src/main/java/com/bytecat/algui/view/EmptyBlurImpl.java b/app/src/main/java/com/bytecat/algui/view/EmptyBlurImpl.java new file mode 100644 index 0000000..ba22b64 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/EmptyBlurImpl.java @@ -0,0 +1,21 @@ +package com.bytecat.algui.view; + +import android.content.Context; +import android.graphics.Bitmap; + +public class EmptyBlurImpl implements BlurImpl { + @Override + public boolean prepare(Context context, Bitmap buffer, float radius) { + return false; + } + + @Override + public void release() { + + } + + @Override + public void blur(Bitmap input, Bitmap output) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/view/RealtimeBlurView.java b/app/src/main/java/com/bytecat/algui/view/RealtimeBlurView.java new file mode 100644 index 0000000..39f14bc --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/RealtimeBlurView.java @@ -0,0 +1,272 @@ +package com.bytecat.algui.view; + +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewTreeObserver; + +/** + * @noinspection ALL + */ +public class RealtimeBlurView extends View { + + private float mDownSampleFactor; + private int mOverlayColor; + private float mBlurRadius; + + private final BlurImpl mBlurImpl; + private boolean mDirty; + private Bitmap mBitmapToBlur, mBlurredBitmap; + private Canvas mBlurringCanvas; + private boolean mIsRendering; + private final Paint mPaint; + private final Rect mRectSrc = new Rect(), mRectDst = new Rect(); + + private View mDecorView; + + private boolean mDifferentRoot; + private static int RENDERING_COUNT; + private static int BLUR_IMPL; + + public RealtimeBlurView(Context context) { + super(context); + + mBlurImpl = new AndroidStockBlurImpl(); + + mBlurRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics()); + mDownSampleFactor = 4; + mOverlayColor = 0x8C000000; + + mPaint = new Paint(); + } + + public void setBlurRadius(float radius) { + if (mBlurRadius != radius) { + mBlurRadius = radius; + mDirty = true; + invalidate(); + } + } + + public void setDownSampleFactor(float factor) { + if (factor <= 0) { + throw new IllegalArgumentException("DownSample factor must be greater than 0."); + } + + if (mDownSampleFactor != factor) { + mDownSampleFactor = factor; + mDirty = true; + releaseBitmap(); + invalidate(); + } + } + + public void setOverlayColor(int color) { + if (mOverlayColor != color) { + mOverlayColor = color; + invalidate(); + } + } + + private void releaseBitmap() { + if (mBitmapToBlur != null) { + mBitmapToBlur.recycle(); + mBitmapToBlur = null; + } + if (mBlurredBitmap != null) { + mBlurredBitmap.recycle(); + mBlurredBitmap = null; + } + } + + protected void release() { + releaseBitmap(); + mBlurImpl.release(); + } + + protected boolean prepare() { + if (mBlurRadius == 0) { + release(); + return false; + } + + float downSampleFactor = mDownSampleFactor; + float radius = mBlurRadius / downSampleFactor; + if (radius > 25) { + downSampleFactor = downSampleFactor * radius / 25; + radius = 25; + } + + final int width = getWidth(); + final int height = getHeight(); + + int scaledWidth = Math.max(1, (int) (width / downSampleFactor)); + int scaledHeight = Math.max(1, (int) (height / downSampleFactor)); + + boolean dirty = mDirty; + + if (mBlurringCanvas == null || mBlurredBitmap == null + || mBlurredBitmap.getWidth() != scaledWidth + || mBlurredBitmap.getHeight() != scaledHeight) { + dirty = true; + releaseBitmap(); + + boolean r = false; + try { + mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + if (mBitmapToBlur == null) { + return false; + } + mBlurringCanvas = new Canvas(mBitmapToBlur); + + mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + if (mBlurredBitmap == null) { + return false; + } + + r = true; + } catch (OutOfMemoryError e) { + } finally { + if (!r) { + release(); + return false; + } + } + } + + if (dirty) { + if (mBlurImpl.prepare(getContext(), mBitmapToBlur, radius)) { + mDirty = false; + } else { + return false; + } + } + + return true; + } + + protected void blur(Bitmap bitmapToBlur, Bitmap blurredBitmap) { + mBlurImpl.blur(bitmapToBlur, blurredBitmap); + } + + private final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + final int[] locations = new int[2]; + Bitmap oldBmp = mBlurredBitmap; + View decor = mDecorView; + if (decor != null && isShown() && prepare()) { + boolean redrawBitmap = mBlurredBitmap != oldBmp; + decor.getLocationOnScreen(locations); + int x = -locations[0]; + int y = -locations[1]; + + getLocationOnScreen(locations); + x += locations[0]; + y += locations[1]; + + mBitmapToBlur.eraseColor(mOverlayColor & 0xffffff); + + int rc = mBlurringCanvas.save(); + mIsRendering = true; + RENDERING_COUNT++; + try { + mBlurringCanvas.scale(1.f * mBitmapToBlur.getWidth() / getWidth(), 1.f * mBitmapToBlur.getHeight() / getHeight()); + mBlurringCanvas.translate(-x, -y); + if (decor.getBackground() != null) { + decor.getBackground().draw(mBlurringCanvas); + } + decor.draw(mBlurringCanvas); + } catch (StopException ignored) { + } finally { + mIsRendering = false; + RENDERING_COUNT--; + mBlurringCanvas.restoreToCount(rc); + } + + blur(mBitmapToBlur, mBlurredBitmap); + + if (redrawBitmap || mDifferentRoot) { + invalidate(); + } + } + + return true; + } + }; + + protected View getActivityDecorView() { + Context ctx = getContext(); + for (int i = 0; i < 4 && !(ctx instanceof Activity) && ctx instanceof ContextWrapper; i++) { + ctx = ((ContextWrapper) ctx).getBaseContext(); + } + if (ctx instanceof Activity) { + return ((Activity) ctx).getWindow().getDecorView(); + } else { + return null; + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mDecorView = getActivityDecorView(); + if (mDecorView != null) { + mDecorView.getViewTreeObserver().addOnPreDrawListener(preDrawListener); + mDifferentRoot = mDecorView.getRootView() != getRootView(); + if (mDifferentRoot) { + mDecorView.postInvalidate(); + } + } else { + mDifferentRoot = false; + } + } + + @Override + protected void onDetachedFromWindow() { + if (mDecorView != null) { + mDecorView.getViewTreeObserver().removeOnPreDrawListener(preDrawListener); + } + release(); + super.onDetachedFromWindow(); + } + + @Override + public void draw(Canvas canvas) { + if (mIsRendering) { + throw STOP_EXCEPTION; + } else if (RENDERING_COUNT > 0) { + } else { + super.draw(canvas); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + drawBlurredBitmap(canvas, mBlurredBitmap, mOverlayColor); + } + + protected void drawBlurredBitmap(Canvas canvas, Bitmap blurredBitmap, int overlayColor) { + if (blurredBitmap != null) { + mRectSrc.right = blurredBitmap.getWidth(); + mRectSrc.bottom = blurredBitmap.getHeight(); + mRectDst.right = getWidth(); + mRectDst.bottom = getHeight(); + canvas.drawBitmap(blurredBitmap, mRectSrc, mRectDst, null); + } + mPaint.setColor(overlayColor); + canvas.drawRect(mRectDst, mPaint); + } + + private static class StopException extends RuntimeException { + } + + private static final StopException STOP_EXCEPTION = new StopException(); +} \ No newline at end of file diff --git a/app/src/main/java/com/bytecat/algui/view/RoundRectDrawable.java b/app/src/main/java/com/bytecat/algui/view/RoundRectDrawable.java new file mode 100644 index 0000000..b34a4e7 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/RoundRectDrawable.java @@ -0,0 +1,208 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytecat.algui.view; + +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + +/** + * Very simple drawable that draws a rounded rectangle background with arbitrary corners and also + * reports proper outline for Lollipop. + *

+ * Simpler and uses less resources compared to GradientDrawable or ShapeDrawable. + */ +class RoundRectDrawable extends Drawable { + private float mRadius; + private final Paint mPaint; + private final RectF mBoundsF; + private final Rect mBoundsI; + private float mPadding; + private boolean mInsetForPadding = false; + private boolean mInsetForRadius = true; + + private ColorStateList mBackground; + private PorterDuffColorFilter mTintFilter; + private ColorStateList mTint; + private PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_IN; + + RoundRectDrawable(ColorStateList backgroundColor, float radius) { + mRadius = radius; + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + setBackground(backgroundColor); + + mBoundsF = new RectF(); + mBoundsI = new Rect(); + } + + private void setBackground(ColorStateList color) { + mBackground = (color == null) ? ColorStateList.valueOf(Color.TRANSPARENT) : color; + mPaint.setColor(mBackground.getColorForState(getState(), mBackground.getDefaultColor())); + } + + void setPadding(float padding, boolean insetForPadding, boolean insetForRadius) { + if (padding == mPadding && mInsetForPadding == insetForPadding + && mInsetForRadius == insetForRadius) { + return; + } + mPadding = padding; + mInsetForPadding = insetForPadding; + mInsetForRadius = insetForRadius; + updateBounds(null); + invalidateSelf(); + } + + float getPadding() { + return mPadding; + } + + @Override + public void draw(Canvas canvas) { + final Paint paint = mPaint; + + final boolean clearColorFilter; + if (mTintFilter != null && paint.getColorFilter() == null) { + paint.setColorFilter(mTintFilter); + clearColorFilter = true; + } else { + clearColorFilter = false; + } + + canvas.drawRoundRect(mBoundsF, mRadius, mRadius, paint); + + if (clearColorFilter) { + paint.setColorFilter(null); + } + } + + private void updateBounds(Rect bounds) { + if (bounds == null) { + bounds = getBounds(); + } + mBoundsF.set(bounds.left, bounds.top, bounds.right, bounds.bottom); + mBoundsI.set(bounds); + if (mInsetForPadding) { + float vInset = RoundRectDrawableWithShadow.calculateVerticalPadding(mPadding, mRadius, mInsetForRadius); + float hInset = RoundRectDrawableWithShadow.calculateHorizontalPadding(mPadding, mRadius, mInsetForRadius); + mBoundsI.inset((int) Math.ceil(hInset), (int) Math.ceil(vInset)); + // to make sure they have same bounds. + mBoundsF.set(mBoundsI); + } + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + updateBounds(bounds); + } + + @Override + public void getOutline(Outline outline) { + outline.setRoundRect(mBoundsI, mRadius); + } + + void setRadius(float radius) { + if (radius == mRadius) { + return; + } + mRadius = radius; + updateBounds(null); + invalidateSelf(); + } + + @Override + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter cf) { + mPaint.setColorFilter(cf); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + public float getRadius() { + return mRadius; + } + + public void setColor(ColorStateList color) { + setBackground(color); + invalidateSelf(); + } + + public ColorStateList getColor() { + return mBackground; + } + + @Override + public void setTintList(ColorStateList tint) { + mTint = tint; + mTintFilter = createTintFilter(mTint, mTintMode); + invalidateSelf(); + } + + @Override + public void setTintMode(PorterDuff.Mode tintMode) { + mTintMode = tintMode; + mTintFilter = createTintFilter(mTint, mTintMode); + invalidateSelf(); + } + + @Override + protected boolean onStateChange(int[] stateSet) { + final int newColor = mBackground.getColorForState(stateSet, mBackground.getDefaultColor()); + final boolean colorChanged = newColor != mPaint.getColor(); + if (colorChanged) { + mPaint.setColor(newColor); + } + if (mTint != null && mTintMode != null) { + mTintFilter = createTintFilter(mTint, mTintMode); + return true; + } + return colorChanged; + } + + @Override + public boolean isStateful() { + return (mTint != null && mTint.isStateful()) + || (mBackground != null && mBackground.isStateful()) || super.isStateful(); + } + + /** + * Ensures the tint filter is consistent with the current tint color and + * mode. + */ + private PorterDuffColorFilter createTintFilter(ColorStateList tint, PorterDuff.Mode tintMode) { + if (tint == null || tintMode == null) { + return null; + } + final int color = tint.getColorForState(getState(), Color.TRANSPARENT); + return new PorterDuffColorFilter(color, tintMode); + } +} diff --git a/app/src/main/java/com/bytecat/algui/view/RoundRectDrawableWithShadow.java b/app/src/main/java/com/bytecat/algui/view/RoundRectDrawableWithShadow.java new file mode 100644 index 0000000..c432f67 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/RoundRectDrawableWithShadow.java @@ -0,0 +1,382 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytecat.algui.view; + +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.RadialGradient; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; + +/** + * A rounded rectangle drawable which also includes a shadow around. + */ +class RoundRectDrawableWithShadow extends Drawable { + // used to calculate content padding + private static final double COS_45 = Math.cos(Math.toRadians(45)); + + private static final float SHADOW_MULTIPLIER = 1.5f; + + private final int mInsetShadow = 1; // extra shadow to avoid gaps between card and shadow + + /* + * This helper is set by CardView implementations. + *

+ * Prior to API 17, canvas.drawRoundRect is expensive; which is why we need this interface + * to draw efficient rounded rectangles before 17. + * */ + static RoundRectHelper sRoundRectHelper; + + private Paint mPaint; + + private Paint mCornerShadowPaint; + + private Paint mEdgeShadowPaint; + + private final RectF mCardBounds; + + private float mCornerRadius; + + private Path mCornerShadowPath; + + // actual value set by developer + private float mRawMaxShadowSize; + + // multiplied value to account for shadow offset + private float mShadowSize; + + // actual value set by developer + private float mRawShadowSize; + + private ColorStateList mBackground; + + private boolean mDirty = true; + + private final int mShadowStartColor = Color.parseColor("#37000000"); + + private final int mShadowEndColor = Color.parseColor("#03000000"); + + private boolean mAddPaddingForCorners = true; + + /** + * If shadow size is set to a value above max shadow, we print a warning + */ + private boolean mPrintedShadowClipWarning = false; + + RoundRectDrawableWithShadow(Resources resources, ColorStateList backgroundColor, float radius, + float shadowSize, float maxShadowSize) { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + setBackground(backgroundColor); + mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + mCornerShadowPaint.setStyle(Paint.Style.FILL); + mCornerRadius = (int) (radius + 0.5f); + mCardBounds = new RectF(); + mEdgeShadowPaint = new Paint(mCornerShadowPaint); + mEdgeShadowPaint.setAntiAlias(false); + setShadowSize(shadowSize, maxShadowSize); + } + + private void setBackground(ColorStateList color) { + mBackground = (color == null) ? ColorStateList.valueOf(Color.TRANSPARENT) : color; + mPaint.setColor(mBackground.getColorForState(getState(), mBackground.getDefaultColor())); + } + + /** + * Casts the value to an even integer. + */ + private int toEven(float value) { + int i = (int) (value + .5f); + if (i % 2 == 1) { + return i - 1; + } + return i; + } + + void setAddPaddingForCorners(boolean addPaddingForCorners) { + mAddPaddingForCorners = addPaddingForCorners; + invalidateSelf(); + } + + @Override + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + mCornerShadowPaint.setAlpha(alpha); + mEdgeShadowPaint.setAlpha(alpha); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + mDirty = true; + } + + private void setShadowSize(float shadowSize, float maxShadowSize) { + if (shadowSize < 0f) { + throw new IllegalArgumentException("Invalid shadow size " + shadowSize + + ". Must be >= 0"); + } + if (maxShadowSize < 0f) { + throw new IllegalArgumentException("Invalid max shadow size " + maxShadowSize + + ". Must be >= 0"); + } + shadowSize = toEven(shadowSize); + maxShadowSize = toEven(maxShadowSize); + if (shadowSize > maxShadowSize) { + shadowSize = maxShadowSize; + if (!mPrintedShadowClipWarning) { + mPrintedShadowClipWarning = true; + } + } + if (mRawShadowSize == shadowSize && mRawMaxShadowSize == maxShadowSize) { + return; + } + mRawShadowSize = shadowSize; + mRawMaxShadowSize = maxShadowSize; + mShadowSize = (int) (shadowSize * SHADOW_MULTIPLIER + mInsetShadow + .5f); + mDirty = true; + invalidateSelf(); + } + + @Override + public boolean getPadding(Rect padding) { + int vOffset = (int) Math.ceil(calculateVerticalPadding(mRawMaxShadowSize, mCornerRadius, + mAddPaddingForCorners)); + int hOffset = (int) Math.ceil(calculateHorizontalPadding(mRawMaxShadowSize, mCornerRadius, + mAddPaddingForCorners)); + padding.set(hOffset, vOffset, hOffset, vOffset); + return true; + } + + static float calculateVerticalPadding(float maxShadowSize, float cornerRadius, + boolean addPaddingForCorners) { + if (addPaddingForCorners) { + return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius); + } else { + return maxShadowSize * SHADOW_MULTIPLIER; + } + } + + static float calculateHorizontalPadding(float maxShadowSize, float cornerRadius, + boolean addPaddingForCorners) { + if (addPaddingForCorners) { + return (float) (maxShadowSize + (1 - COS_45) * cornerRadius); + } else { + return maxShadowSize; + } + } + + @Override + protected boolean onStateChange(int[] stateSet) { + final int newColor = mBackground.getColorForState(stateSet, mBackground.getDefaultColor()); + if (mPaint.getColor() == newColor) { + return false; + } + mPaint.setColor(newColor); + mDirty = true; + invalidateSelf(); + return true; + } + + @Override + public boolean isStateful() { + return (mBackground != null && mBackground.isStateful()) || super.isStateful(); + } + + @Override + public void setColorFilter(ColorFilter cf) { + mPaint.setColorFilter(cf); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + void setCornerRadius(float radius) { + if (radius < 0f) { + throw new IllegalArgumentException("Invalid radius " + radius + ". Must be >= 0"); + } + radius = (int) (radius + .5f); + if (mCornerRadius == radius) { + return; + } + mCornerRadius = radius; + mDirty = true; + invalidateSelf(); + } + + @Override + public void draw(Canvas canvas) { + if (mDirty) { + buildComponents(getBounds()); + mDirty = false; + } + canvas.translate(0, mRawShadowSize / 2); + drawShadow(canvas); + canvas.translate(0, -mRawShadowSize / 2); + sRoundRectHelper.drawRoundRect(canvas, mCardBounds, mCornerRadius, mPaint); + } + + private void drawShadow(Canvas canvas) { + final float edgeShadowTop = -mCornerRadius - mShadowSize; + final float inset = mCornerRadius + mInsetShadow + mRawShadowSize / 2; + final boolean drawHorizontalEdges = mCardBounds.width() - 2 * inset > 0; + final boolean drawVerticalEdges = mCardBounds.height() - 2 * inset > 0; + // LT + int saved = canvas.save(); + canvas.translate(mCardBounds.left + inset, mCardBounds.top + inset); + canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); + if (drawHorizontalEdges) { + canvas.drawRect(0, edgeShadowTop, + mCardBounds.width() - 2 * inset, -mCornerRadius, + mEdgeShadowPaint); + } + canvas.restoreToCount(saved); + // RB + saved = canvas.save(); + canvas.translate(mCardBounds.right - inset, mCardBounds.bottom - inset); + canvas.rotate(180f); + canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); + if (drawHorizontalEdges) { + canvas.drawRect(0, edgeShadowTop, + mCardBounds.width() - 2 * inset, -mCornerRadius + mShadowSize, + mEdgeShadowPaint); + } + canvas.restoreToCount(saved); + // LB + saved = canvas.save(); + canvas.translate(mCardBounds.left + inset, mCardBounds.bottom - inset); + canvas.rotate(270f); + canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); + if (drawVerticalEdges) { + canvas.drawRect(0, edgeShadowTop, + mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint); + } + canvas.restoreToCount(saved); + // RT + saved = canvas.save(); + canvas.translate(mCardBounds.right - inset, mCardBounds.top + inset); + canvas.rotate(90f); + canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); + if (drawVerticalEdges) { + canvas.drawRect(0, edgeShadowTop, + mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint); + } + canvas.restoreToCount(saved); + } + + private void buildShadowCorners() { + RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius); + RectF outerBounds = new RectF(innerBounds); + outerBounds.inset(-mShadowSize, -mShadowSize); + + if (mCornerShadowPath == null) { + mCornerShadowPath = new Path(); + } else { + mCornerShadowPath.reset(); + } + mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD); + mCornerShadowPath.moveTo(-mCornerRadius, 0); + mCornerShadowPath.rLineTo(-mShadowSize, 0); + // outer arc + mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false); + // inner arc + mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false); + mCornerShadowPath.close(); + float startRatio = mCornerRadius / (mCornerRadius + mShadowSize); + mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize, + new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, + new float[]{0f, startRatio, 1f}, + Shader.TileMode.CLAMP)); + + // we offset the content shadowSize/2 pixels up to make it more realistic. + // this is why edge shadow shader has some extra space + // When drawing bottom edge shadow, we use that extra space. + mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0, + -mCornerRadius - mShadowSize, + new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, + new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP)); + mEdgeShadowPaint.setAntiAlias(false); + } + + private void buildComponents(Rect bounds) { + // Card is offset SHADOW_MULTIPLIER * maxShadowSize to account for the shadow shift. + // We could have different top-bottom offsets to avoid extra gap above but in that case + // center aligning Views inside the CardView would be problematic. + final float verticalOffset = mRawMaxShadowSize * SHADOW_MULTIPLIER; + mCardBounds.set(bounds.left + mRawMaxShadowSize, bounds.top + verticalOffset, + bounds.right - mRawMaxShadowSize, bounds.bottom - verticalOffset); + buildShadowCorners(); + } + + float getCornerRadius() { + return mCornerRadius; + } + + void getMaxShadowAndCornerPadding(Rect into) { + getPadding(into); + } + + void setShadowSize(float size) { + setShadowSize(size, mRawMaxShadowSize); + } + + void setMaxShadowSize(float size) { + setShadowSize(mRawShadowSize, size); + } + + float getShadowSize() { + return mRawShadowSize; + } + + float getMaxShadowSize() { + return mRawMaxShadowSize; + } + + float getMinWidth() { + final float content = 2 + * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + mRawMaxShadowSize / 2); + return content + (mRawMaxShadowSize + mInsetShadow) * 2; + } + + float getMinHeight() { + final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + + mRawMaxShadowSize * SHADOW_MULTIPLIER / 2); + return content + (mRawMaxShadowSize * SHADOW_MULTIPLIER + mInsetShadow) * 2; + } + + void setColor(ColorStateList color) { + setBackground(color); + invalidateSelf(); + } + + ColorStateList getColor() { + return mBackground; + } + + interface RoundRectHelper { + void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, Paint paint); + } +} diff --git a/app/src/main/java/com/bytecat/algui/view/SliderView.java b/app/src/main/java/com/bytecat/algui/view/SliderView.java new file mode 100644 index 0000000..05249d5 --- /dev/null +++ b/app/src/main/java/com/bytecat/algui/view/SliderView.java @@ -0,0 +1,226 @@ +package com.bytecat.algui.view; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.view.MotionEvent; +import android.view.View; + +import com.bytecat.algui.callback.SliderCallback; +import android.graphics.RectF; +import android.animation.ValueAnimator; + +public class SliderView extends View { + + private static final int PROGRESS_COLOR = Color.parseColor("#CC7F7FD5"); + private static final int THUMB_COLOR = Color.parseColor("#E6E0E0E6"); + private static final int GLOW_COLOR = Color.parseColor("#CC7F7FD5"); // 光环颜色 + + private final Rect rect; + + private final Paint paint; + private final Paint thumbPaint; + private final Paint glowPaint; + + public SliderCallback sliderCallback; + + + private float originalMax; + + private float originalMin; + + private float max; + + private float progress; + + private int right; + + private boolean isEnabled; + + private float thumbRadius = 15; // 滑块的半径 + private float thumbRadiusPressed = 30; // 滑块按下时的目标半径 + private float glowRadius = 40; // 光环的半径 + private float currentThumbRadius; // 当前滑块半径(用于动画) + private boolean isPressed = false; // 是否按下 + + public SliderView(Context context) { + super(context); + rect = new Rect(); + + paint = new Paint(); + paint.setColor(PROGRESS_COLOR); + paint.setAntiAlias(true); + + thumbPaint = new Paint(); + thumbPaint.setColor(THUMB_COLOR); + thumbPaint.setAntiAlias(true); + + glowPaint = new Paint(); + glowPaint.setColor(GLOW_COLOR); + glowPaint.setAntiAlias(true); + glowPaint.setStyle(Paint.Style.STROKE); // 光环为描边样式 + glowPaint.setStrokeWidth(10); // 光环的宽度 + + setSliderParams(100, 0, 0); + currentThumbRadius = thumbRadius; // 初始化当前滑块半径 + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + + + float progressWidth = progress / max * getWidth(); // 根据进度计算进度条宽度 + canvas.drawRect(0, 0, progressWidth, getHeight(), paint); + + // 绘制滑块(圆形) + float thumbX = progressWidth; // 滑块中心位于进度条终点 + float thumbY = getHeight() / 2f; + // 如果按下,绘制光环 + if (isPressed) { + canvas.drawCircle(thumbX, thumbY, glowRadius, glowPaint); // 绘制光环 + } + + // 绘制滑块,根据动画调整大小 + canvas.drawCircle(thumbX, thumbY, currentThumbRadius, thumbPaint); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + float percent = progress / max; + right = Math.max(Math.min((int) (w * percent), w), 0); + invalidate(); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + + float percent = event.getX() / getWidth(); + float newProgress = Math.max(Math.min(max * percent, max), 0); + right = Math.max(Math.min((int) (getWidth() * percent), getWidth()), 0); + invalidate(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + // 按下时启动放大动画并显示光环 + isPressed = true; + startScaleAnimation(true); + invalidate(); + break; + case MotionEvent.ACTION_MOVE: + // 移动时更新进度 + progress = newProgress; + invalidate(); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + // 释放时启动恢复动画并隐藏光环 + isPressed = false; + startScaleAnimation(false); + invalidate(); + break; + } + + if (sliderCallback != null && isEnabled) { + + sliderCallback.onSlide( + Math.max(Math.min(newProgress + originalMin, originalMax), originalMin), + Math.max(Math.min(progress + originalMin, originalMax), originalMin) + ); + progress = newProgress; + } + return true; + } + + private void startScaleAnimation(boolean isPressing) { + // 动画目标值 + float targetRadius = isPressing ? thumbRadiusPressed : thumbRadius; + + // 使用ValueAnimator实现动画 + ValueAnimator animator = ValueAnimator.ofFloat(currentThumbRadius, targetRadius); + animator.setDuration(200); // 动画时长200ms + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + currentThumbRadius = (float) animation.getAnimatedValue(); // 更新当前滑块半径 + invalidate(); // 重绘视图 + } + }); + + animator.start(); + } + + public void setSliderCallback(SliderCallback sliderCallback) { + this.sliderCallback = sliderCallback; + } + + public void setSliderParams(float max, float min, float progress) { + if (min >= max) { + throw new IllegalArgumentException("min >= max"); + } + if (progress < min) { + progress = min; + } else { + progress -= min; + } + if (progress > max) { + progress = max; + } + + originalMax = max; + originalMin = min; + + this.max = max - min; + this.progress = progress; + + if (getWidth() >= 0) { + float percent = progress / max; + right = Math.max(Math.min((int) (getWidth() * percent), getWidth()), 0); + invalidate(); + } + } + + public float getMax() { + return originalMax; + } + + public float getMin() { + return originalMin; + } + + public float getProgress() { + + return Math.max(Math.min(progress + originalMin, originalMax), originalMin); // 使用 originalMin 作为下限} + + } + public void setMax(float max) { + setSliderParams(max, getMin(), getProgress()); + } + + public void setMin(float min) { + setSliderParams(getMax(), min, getProgress()); + } + + public void setProgress(float progress) { + setSliderParams(getMax(), getMin(), progress); + } + + public void setThumbRadius(float radius) { + this.thumbRadius = radius; + invalidate(); + } + + public void setEnabled1(boolean isEnabled) { + this.isEnabled = isEnabled; + } + +} diff --git a/app/src/main/jni/AlguiLog.h b/app/src/main/jni/AlguiLog.h new file mode 100644 index 0000000..3d07f8b --- /dev/null +++ b/app/src/main/jni/AlguiLog.h @@ -0,0 +1,112 @@ +#pragma once +#include +#include +#include +#include +//Algui日志相关 +//作者:ByteCat *_* 作者QQ:3353484607 游戏逆向交流QQ群:931212209 + +//安卓日志 +#define ALOGTAG "ALGUI" +#define ALOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOGTAG, __VA_ARGS__))//信息 +#define ALOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOGTAG, __VA_ARGS__))//警告 +#define ALOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOGTAG, __VA_ARGS__))//调试 +#define ALOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOGTAG, __VA_ARGS__))//错误 + +//Algui日志 +//日志优先级 +#define ALGUI_LOG_UNKNOWN 0 /** 仅供内部使用。 */ +#define ALGUI_LOG_DEFAULT 1 /** 默认优先级,仅供内部使用。 */ +#define ALGUI_LOG_VERBOSE 2 /** 详细日志。通常在发布版 apk 中应禁用。 */ +#define ALGUI_LOG_DEBUG 3 /** 调试日志。通常在发布版 apk 中应禁用。 */ +#define ALGUI_LOG_INFO 4 /** 信息日志。通常在发布版 apk 中应禁用。 */ +#define ALGUI_LOG_WARN 5 /** 警告日志。用于可恢复的故障。 */ +#define ALGUI_LOG_ERROR 6 /** 错误日志。用于不可恢复的故障。 */ +#define ALGUI_LOG_FATAL 7 /** 致命日志。用于中止时。 */ +#define ALGUI_LOG_SILENT 8 /** 仅供内部使用。 */ + +#define ALGUILOGFILE "/storage/emulated/0/Android/内部调试.txt"//Algui日志输出文件路径 + +#define LOG(priority, tag, ...) \ + ((void)__algui_log_print__(priority, tag, __VA_ARGS__))// 自定义日志宏 +#define LOGV(tag, ...) LOG(ALGUI_LOG_VERBOSE, tag, __VA_ARGS__)// 详细级别日志宏 /** 通常在发布版 apk 中应禁用。 */ +#define LOGD(tag, ...) LOG(ALGUI_LOG_DEBUG, tag, __VA_ARGS__)// 调试级别日志宏 /** 通常在发布版 apk 中应禁用。 */ +#define LOGI(tag, ...) LOG(ALGUI_LOG_INFO, tag, __VA_ARGS__)// 信息级别日志宏 /** 通常在发布版 apk 中应禁用。 */ +#define LOGW(tag, ...) LOG(ALGUI_LOG_WARN, tag, __VA_ARGS__)// 警告级别日志宏 /** 用于可恢复的故障。 */ +#define LOGE(tag, ...) LOG(ALGUI_LOG_ERROR, tag, __VA_ARGS__)// 错误级别日志宏 /** 用于不可恢复的故障。 */ +#define LOGF(tag, ...) LOG(ALGUI_LOG_FATAL, tag, __VA_ARGS__)// 致命级别日志宏 /** 用于中止时。 */ + + +const char* __priorityToString__(int priority);//将优先级映射到字符串 +int __algui_log_print__(int priority, const char* tag, const char* format, ...);//在Algui日志文件中写入一行信息 + + + +///

+/// 将优先级映射到字符串 +/// +/// 优先级id +/// 优先级字符串 +const char* __priorityToString__(int priority) { + switch (priority) { + case ALGUI_LOG_VERBOSE: return "VERBOSE"; + case ALGUI_LOG_DEBUG: return "DEBUG"; + case ALGUI_LOG_INFO: return "INFO"; + case ALGUI_LOG_WARN: return "WARN"; + case ALGUI_LOG_ERROR: return "ERROR"; + case ALGUI_LOG_FATAL: return "FATAL"; + case ALGUI_LOG_SILENT: return "SILENT"; + case ALGUI_LOG_UNKNOWN: + default: return "UNKNOWN"; + } +} +/// +/// 在Algui日志文件中写入一行信息 +/// +/// 优先级 +/// 日志标签 +/// 日志信息 +/// 日志信息可变参数 +/// 成功与否 +int __algui_log_print__(int priority, const char* tag, const char* format, ...) { + //以追加模式打开文件 + FILE* file = fopen(ALGUILOGFILE, "a"); + if (file == nullptr) { + return -1; + } + + //获取当前时间 + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + //将时间转换为本地时间 + time_t now = ts.tv_sec; + struct tm* timeinfo = localtime(&now); + + //打印时间戳 + fprintf(file, "[%04d-%02d-%02d %02d:%02d:%02d.%03ld] ", + timeinfo->tm_year + 1900, + timeinfo->tm_mon + 1, + timeinfo->tm_mday, + timeinfo->tm_hour, + timeinfo->tm_min, + timeinfo->tm_sec, + ts.tv_nsec / 1000000L); //纳秒转为毫秒 + + //打印日志优先级 + fprintf(file, "[%s] ", __priorityToString__(priority)); + + //打印日志标签 + fprintf(file, "[%s] ", tag); + + //打印信息内容 + va_list args; + va_start(args, format); //初始化 va_list,用于访问可变参数 + vfprintf(file, format, args); //将格式化的日志消息写入文件 + va_end(args); //结束 va_list 的使用 + + fprintf(file, "\n"); //添加换行 + + fclose(file); //关闭文件 + return 0; +} diff --git a/app/src/main/jni/AlguiMemTool.h b/app/src/main/jni/AlguiMemTool.h new file mode 100644 index 0000000..4b60b06 --- /dev/null +++ b/app/src/main/jni/AlguiMemTool.h @@ -0,0 +1,3360 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //kill信号定义在此 + +using namespace std; + +//小白已经在2021年被凌烟kill了 + + + +//AlguiMemTool开源版本:3.0.24109 [🤪警告:仅供Algui外挂模板使用 请勿在其它外挂模板使用可能会发生很多问题] +/* + * MIT License + * + * 版权所有 (c) [2024] ByteCat + * + * 特此授予任何获得本项目及相关文档文件 副本的人,免费使用该软件的权利,包括但不限于使用、复制、修改、合并、出版、分发、再许可和/或出售该软件的副本,以及允许他人这样做,条件如下: + * + * 1. 上述版权声明和本许可声明应包含在所有副本或实质性部分中。 + * 2. 本软件是按“原样”提供的,不附有任何形式的明示或暗示的担保,包括但不限于对适销性、特定用途的适用性和不侵权的担保。 + * 3. 在任何情况下,作者或版权持有人对因使用本项目或与本项目的其他交易而引起的任何索赔、损害或其他责任不承担任何责任,无论是在合同、侵权或其他方面。 + * 4. 请注意,**禁止删除或修改本版权声明和作者信息**,以确保所有用户都能了解软件的来源和许可条款。 + * * **请勿删除下面的信息!** + * 作者:ByteCat *_* + * 游戏逆向交流QQ群:931212209 + * 作者QQ:3353484607 + * 私人定制请联系我 => 接C/C++ Java 安卓开发 联系作者QQ:3353484607 + * 此项目对接到Java请联系我 联系作者QQ:3353484607 + */ + + + + // 更新内容(只列出重要更新): + // 0. 新增完整的联合搜索 完全和GG修改器的联合搜索一样 + // 1. 所有修改内存数据操作 都会对当前进程进行内存保护🛡️ 防止GG模糊搜索 + // 注意:内存保护只对当前进程有效 意味着只有直装能够防模糊 Root修改外部进程时无法防模糊[可能需要附加调试器进行代码注入] + // 所以如果你开发的是Root插件辅助请使用简单粗暴的方式 直接调用killGG_Root();方法来杀掉GG修改器 + // 2. Ca内存已适配android11+ scudo内存分配器 修复了某些Ca内存数据搜不到 + // 3. 完全兼容了模拟器架构 + // 4. 内存搜索已支持范围搜索 例如:10~20 + // 5. 动静态基址修改 已兼容所有基址头 HEAD_XA,HEAD_CD,HEAD_CB + // 6. 所有修改内存数据操作 新增冻结修改 例如:MemoryOffsetWrite("99999", TYPE_DWORD, 0, true); 将bool参数改为true则冻结 否则改为false则停止冻结 + // 7. 新增打印搜索结果列表到指定文件 和 打印冻结列表到指定文件的 调试方法 + // 8. 新增所有常用数据类型和常用内存范围 + // 9. 重写了所有内存筛选规则,对于内存筛选更加精准了 + // 10. 新增一些Root跨进程工具 + // 11. 很多逻辑都进行了原理注释 让新手更好学习 + // + // 2024-10-9 更新内容: + // 0. 联合搜索增加了对范围联合搜索的支持 例:0.1F;3~6D;9 + // 1. 新增内存改善 休眠进程 解冻进程 + // 2. 偏移改善增加了对范围改善和联合改善的支持 + // 2. ~偏移联合改善 -适用于:某些副特征码会变化但是永远只会变为那几个固定值的情况 比如只会变化为22或15或27时可以使用偏移联合改善22;15;27 + // 2. ~偏移范围改善 -适用于:某些副特征码会变化但是只会在一个范围之内变化时 比如特征码始终为1或2或3时 可以使用偏移范围改善使用1~3即可 + // 3. 优化搜索速度 + // 4. 修复潜在溢出 + // 5. 修复一亿个bug + + //初始化ABI字符串 +#if defined(__arm__) && !defined(__aarch64__) //针对 ARM 32 位架构 +#define ABI "ARM32" +#elif defined(__aarch64__) //针对 ARM 64 位架构 +#define ABI "ARM64" +#elif defined(__x86_64__) || defined(_M_X64) //针对 x64 架构 +#define ABI "x64" +#elif defined(__i386__) || defined(_M_IX86) //针对 x86 架构 +#define ABI "x86" +#else // 其他架构或未知架构 +#define ABI "null" +#endif +//内存区域 +#define RANGE_ALL 0 // 所有内存区域 - 全部内存 +#define RANGE_JAVA_HEAP 2 // Java 虚拟机堆内存 - jh内存 +#define RANGE_C_HEAP 1 // C++ 堆内存 - ch内存 +#define RANGE_C_ALLOC 4 // C++ 分配的内存 - ca内存 [已适配 android11+ scudo内存分配器] +#define RANGE_C_DATA 8 // C++ 的数据段 - cd内存 +#define RANGE_C_BSS 16 // C++ 未初始化的数据 - cb内存 +#define RANGE_ANONYMOUS 32 // 匿名内存区域 - a内存 +#define RANGE_JAVA 65536 // Java 虚拟机内存 - j内存 +#define RANGE_STACK 64 // 栈内存区域 - s内存 +#define RANGE_ASHMEM 524288 // Android 共享内存 - as内存 +#define RANGE_VIDEO 1048576 // 视频内存区域 - v内存 +#define RANGE_OTHER -2080896 // 其他内存区域 - o内存 +#define RANGE_B_BAD 131072 // 错误的内存区域 - b内存 +#define RANGE_CODE_APP 16384 // 应用程序代码区域 - xa内存 +#define RANGE_CODE_SYSTEM 32768 // 系统代码区域 - xs内存 + +#if defined(__arm__) || defined(__aarch64__) //arm32和arm64架构 +#define BCMAPSFLAG(mapLine, id) \ + (\ + (id) == RANGE_ALL ? true: \ + (id) == RANGE_JAVA_HEAP ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "dalvik-")!=NULL) : \ + (id) == RANGE_C_HEAP ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[heap]")!=NULL) : \ + (id) == RANGE_C_ALLOC ? (strstr(mapLine, "rw")!=NULL && (strstr(mapLine, "[anon:libc_malloc]")!=NULL || strstr(mapLine,"[anon:scudo")!=NULL)) : \ + (id) == RANGE_C_DATA ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "xp")==NULL && (strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL||strstr(mapLine, "/data/user/")!=NULL)) : \ + (id) == RANGE_C_BSS ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[anon:.bss]")!=NULL) : \ + (id) == RANGE_ANONYMOUS ? (strstr(mapLine, "rw")!=NULL && strchr(mapLine, '[') == NULL && strchr(mapLine, '/') == NULL) : \ + (id) == RANGE_JAVA ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "dalvik-")!=NULL) : \ + (id) == RANGE_STACK ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[stack")!=NULL) : \ + (id) == RANGE_ASHMEM ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "xp")==NULL && strstr(mapLine, "/dev/ashmem/")!=NULL && strstr(mapLine,"dalvik")==NULL) : \ + (id) == RANGE_VIDEO ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "/dev/mali")!=NULL) : \ + (id) == RANGE_B_BAD ? (strstr(mapLine, "r")!=NULL && (strstr(mapLine, "kgsl-3d0")!=NULL||strstr(mapLine, ".ttf")!=NULL)) : \ + (id) == RANGE_CODE_APP ? (strstr(mapLine, " r")!=NULL && strstr(mapLine, "xp")!=NULL && (strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL || (strstr(mapLine, "/dev/ashmem/")!=NULL&& strstr(mapLine,"dalvik")!=NULL) ||strstr(mapLine, "/data/user/")!=NULL)) : \ + (id) == RANGE_CODE_SYSTEM ? (strstr(mapLine, " r")!=NULL && strstr(mapLine, "xp")!=NULL && (strstr(mapLine, "/system")!=NULL || strstr(mapLine, "/vendor") !=NULL || strstr(mapLine, "/apex") !=NULL || strstr(mapLine, "/memfd") !=NULL || strstr(mapLine, "[vdso")!=NULL)) : \ + (id) == RANGE_OTHER ? (strstr(mapLine, "rw")!=NULL && !(strstr(mapLine, "dalvik-")!=NULL||strstr(mapLine, "[heap]")!=NULL||strstr(mapLine, "[anon:libc_malloc]")!=NULL || strstr(mapLine,"[anon:scudo")!=NULL || strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL ||strstr(mapLine, "/data/user/")!=NULL|| strstr(mapLine, "[anon:.bss]")!=NULL || (strchr(mapLine, '[') == NULL && strchr(mapLine, '/') == NULL) ||strstr(mapLine, "[stack")!=NULL||strstr(mapLine, "/dev/ashmem/")!=NULL||strstr(mapLine, "/dev/mali")!=NULL||strstr(mapLine, "kgsl-3d0")!=NULL||strstr(mapLine, ".ttf")!=NULL||strstr(mapLine, "/system")!=NULL||strstr(mapLine, "/vendor")!=NULL||strstr(mapLine, "/apex")!=NULL||strstr(mapLine, "/memfd")!=NULL||strstr(mapLine, "[vdso")!=NULL)) : \ + true\ + ) +#else //x86和x64架构 针对雷电9模拟器《已知bug:cd可能会多搜到一些xa的数据》 +#define BCMAPSFLAG(mapLine, id) \ + (\ + (id) == RANGE_ALL ? true: \ + (id) == RANGE_JAVA_HEAP ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "dalvik-")!=NULL) : \ + (id) == RANGE_C_HEAP ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[heap]")!=NULL) : \ + (id) == RANGE_C_ALLOC ? (strstr(mapLine, "rw")!=NULL && (strstr(mapLine, "[anon:libc_malloc]")!=NULL || strstr(mapLine,"[anon:scudo")!=NULL)) : \ + (id) == RANGE_C_DATA ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "xp")==NULL && (strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL||strstr(mapLine, "/data/user/")!=NULL)) : \ + (id) == RANGE_C_BSS ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[anon:.bss]")!=NULL) : \ + (id) == RANGE_ANONYMOUS ? (strstr(mapLine, "rw")!=NULL && strchr(mapLine, '[') == NULL && strchr(mapLine, '/') == NULL) : \ + (id) == RANGE_JAVA ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "dalvik-")!=NULL) : \ + (id) == RANGE_STACK ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[stack")!=NULL) : \ + (id) == RANGE_ASHMEM ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "xp")==NULL && strstr(mapLine, "/dev/ashmem/")!=NULL && strstr(mapLine,"dalvik")==NULL) : \ + (id) == RANGE_VIDEO ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "/dev/mali")!=NULL) : \ + (id) == RANGE_B_BAD ? (strstr(mapLine, "r")!=NULL && (strstr(mapLine, "kgsl-3d0")!=NULL||strstr(mapLine, ".ttf")!=NULL)) : \ + (id) == RANGE_CODE_APP ? (strstr(mapLine, " r")!=NULL && (strstr(mapLine, "xp")!=NULL||strstr(mapLine, "--p")!=NULL) && (strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL || (strstr(mapLine, "/dev/ashmem/")!=NULL&& strstr(mapLine,"dalvik")!=NULL) ||strstr(mapLine, "/data/user/")!=NULL)) : \ + (id) == RANGE_CODE_SYSTEM ? (strstr(mapLine, " r")!=NULL && (strstr(mapLine, "xp")!=NULL||strstr(mapLine, "--p")!=NULL) && (strstr(mapLine, "/system")!=NULL || strstr(mapLine, "/vendor") !=NULL || strstr(mapLine, "/apex") !=NULL || strstr(mapLine, "/memfd") !=NULL || strstr(mapLine, "[vdso")!=NULL)) : \ + (id) == RANGE_OTHER ? (strstr(mapLine, "rw") != NULL && !(strstr(mapLine, "dalvik-") != NULL || strstr(mapLine, "[heap]") != NULL || strstr(mapLine, "[anon:libc_malloc]") != NULL || strstr(mapLine, "[anon:scudo") != NULL || strstr(mapLine, "/data/app/") != NULL || strstr(mapLine, "/data/data/") != NULL || strstr(mapLine, "/data/user/") != NULL || strstr(mapLine, "[anon:.bss]") != NULL || (strchr(mapLine, '[') == NULL && strchr(mapLine, '/') == NULL) || strstr(mapLine, "[stack") != NULL || strstr(mapLine, "/dev/ashmem/") != NULL || strstr(mapLine, "/dev/mali") != NULL || strstr(mapLine, "kgsl-3d0") != NULL || strstr(mapLine, ".ttf") != NULL || strstr(mapLine, "/system") != NULL || strstr(mapLine, "/vendor") != NULL || strstr(mapLine, "/apex") != NULL || strstr(mapLine, "/memfd") != NULL || strstr(mapLine, "[vdso") != NULL)) : \ + true\ + ) +#endif +//(id) == RANGE_OTHER ? (strstr(mapLine, "rw") != NULL && strstr(mapLine, "[anon:mmv8]")!=NULL) : \ + +//基址头 +#define HEAD_XA 0 //xa基址头 +#define HEAD_CD 1 //cd基址头 +#define HEAD_CB 2 //cb基址头 [bss] + +//数据类型 +#define TYPE_DWORD 4 // DWORD 类型 - D类型 +#define TYPE_FLOAT 16 // FLOAT 类型 - F类型 +#define TYPE_DOUBLE 64 // DOUBLE 类型 - E类型 +#define TYPE_WORD 2 // WORD 类型 - W类型 +#define TYPE_BYTE 1 // BYTE 类型 - B类型 +#define TYPE_QWORD 32 // QWORD 类型 - Q类型 + +//映射数据类型别名 方便管理 +#define DWORD int32_t // 32 位有符号整数 +#define FLOAT float // 单精度浮点数 +#define DOUBLE double // 双精度浮点数 +#define WORD signed short // 有符号短整型 +#define BYTE signed char // 有符号字符 +#define QWORD int64_t // 64 位有符号整数 + +//范围搜索格式 +#define R_SEPARATE "~" // 范围搜索符号 + +//联合搜索格式 +#define U_DEFRANGE 512 // 默认搜索附近范围 +#define U_SEPARATE ";" // 数据分隔符 +#define U_RANGESEPARATE ":" // 数据范围符【存在两个此符号将视为按顺序搜索】 +#define U_dword "d" // 32 位有符号整数 +#define U_float "f" // 单精度浮点数 +#define U_double "e" // 双精度浮点数 +#define U_word "w" // 有符号短整型 +#define U_byte "b" // 有符号字符 +#define U_qword "q" // 64 位有符号整数 +#define U_DWORD "D" // 32 位有符号整数的大写 +#define U_FLOAT "F" // 单精度浮点数的大写 +#define U_DOUBLE "E" // 双精度浮点数的大写 +#define U_WORD "W" // 有符号短整型的大写 +#define U_BYTE "B" // 有符号字符的大写 +#define U_QWORD "Q" // 64 位有符号整数的大写 + +#define FLAG_FREE "FREE" //修改时只进行冻结的标志 +//结构体声明: +struct Item;//内存数据项 +struct Federated;//联合搜索项 +struct Protection;//内存保护-防模糊优化 +//全局变量 +bool isInit = false;//是否进行了初始化 +bool isSecureWrites = false;//是否进行安全写入 +bool isMapsMemArea = false;//是否为自定义内存区域 +int pid = -1;//存储进程ID +char* packName;//存储进程包名 +int memory = RANGE_ALL;//存储要搜索的内存区域【默认所有内存】 +char* memoryMaps;//存储自定义要搜索的内存区域【maps内存段 使用自定义内存区域可以精准搜索并且提升100倍搜索速度】 +char memPath[1024];//存储进程mem内存映射虚拟文件路径 +char mapsPath[1024];//存储进程maps内存区域映射文件路径 +uint32_t freezeDelay = 200;//冻结修改延迟(毫秒)默认200ms +static bool isFreeze;//是否正在冻结 确保只开一个冻结线程 +vector < Item > FreezeList;//冻结修改项列表 +vector < unsigned long >outcomeList;//最终搜索结果列表 - 存储最终筛选出的数据的内存地址列表 +vector < Protection > ProtectList;//保护项列表 +std::mutex lockMutex;//互斥锁 防止全局数据竞争 + +//函数声明: +//初始化 +int getPID(const char* packageName);// 获取进程ID +int setPackageName(const char* packageName);// 设置目标包名 【注意:这是初始化函数,不调用此函数的话其它内存操作均失效】 +void setIsSecureWrites(bool sw);// 设置安全写入启用状态 + + +//模块[动/静]态基址偏移内存修改 +unsigned long getModuleBaseAddr(const char* module_name, int headType);//获取模块起始地址(基址) +unsigned long jump(unsigned long addr,int count);//跳转指针 +unsigned long jump32(unsigned long addr);//跳转指针 [32位] +unsigned long jump64(unsigned long addr);//跳转指针 [64位] +int setMemoryAddrValue(const char* value, unsigned long addr, int type, bool isFree,bool isSecure);//设置指定内存地址指向的值 🛡️该方法已对当前进程进行保护 防止GG模糊🛡️ +char* getMemoryAddrData(unsigned long addr, int type);//获取指定内存地址的数据 + +//内存搜索 +void setMemoryArea(int memoryArea);//设置要搜索的内存区域 +void setMemoryArea(const char* memoryArea);//设置自定义搜索的内存区域 好处:能精准找到想要的数据,并且搜索速度直接提升100倍 坏处:需要自己去找数据所在的maps内存段 示例:setMemoryArea("/apex/com.android.tethering/lib64/libframework-connectivity-jni.so"); +vector < unsigned long > MemorySearch(const char* value, int type);//内存搜索 【支持范围搜索 格式:最小值~最大值(同GG) 支持联合搜索 格式:值1;值2;值3;n个值:范围 示例:2D;3F;4E:50 或 2D;3F;4E没有范围则使用默认范围,两个范围符::代表按顺序搜索 (同GG)】 +vector < unsigned long > MemorySearchRange(const char* value, int type);//范围内存搜索 【格式:最小值~最大值 (同GG)】 +vector < unsigned long > MemorySearchUnited(const char* value, int type);//联合内存搜索 【格式:值1;值2;值3;n个值:附近范围 示例:2D;3F;4E:50 或 2D;3F;4E没有范围则使用默认范围,两个范围符::代表按顺序搜索 (同GG) 并且值也支持范围例如1~2;3:64】 +vector < unsigned long > ImproveOffset(const char* value, int type, unsigned long offset);//偏移改善 [筛选偏移处特征值 支持联合改善,范围改善] +vector < unsigned long > ImproveOffsetRange(const char* value, int type, unsigned long offset);//偏移范围改善 [筛选偏移处只会在一个范围内变化的特征值] 【格式:最小值~最大值 (同GG)】 +vector < unsigned long > ImproveOffsetUnited(const char* value, int type, unsigned long offset);//偏移联合改善 [筛选偏移处永远只会为某些值的特征值] 【格式:值1;值2;n个值; 示例:2D;3F;4E 或 2D;3~6F;9E 注:联合改善不支持附近范围和顺序改善】 +vector < unsigned long > ImproveValue(const char* value, int type);//改善 [支持联合改善,范围改善] +int MemoryOffsetWrite(const char* value,int type, unsigned long offset, bool isFree,bool isSecure);//结果偏移写入数据 🛡️该方法已对当前进程进行保护 防止GG模糊🛡️ +int getResultCount();//获取最终搜索结果数量 +vector < unsigned long > getResultList();//获取最终搜索结果列表 +int printResultListToFile(const char* filePath);//打印最终搜索结果列表到指定文件 +int clearResultList();//清空最终搜索结果列表 + +//内存保护二次修改 +void MemoryProtect(unsigned long addr); +int getProtectionNum(); +//冻结内存修改 +vector < Item > getFreezeList();//获取冻结修改项列表 +void setFreezeDelayMs(uint32_t delay);//设置冻结修改延迟【毫秒】 +int getFreezeNum();//获取冻结修改项数量 +int addFreezeItem(const char* value, unsigned long addr, int type); // 添加一个冻结修改项 +int removeFreezeItem(unsigned long addr); // 移除一个冻结修改项 +int removeAllFreezeItem();//移除所有冻结修改项 +void* freezeThread(void* arg); // 冻结循环修改线程 +int startAllFreeze(); // 开始冻结所有修改项 +int stopAllFreeze(); // 停止冻结所有修改项 +int printFreezeListToFile(const char* filePath);//打印冻结列表到指定文件 + +//获取内存信息相关工具 +char* getMemoryAddrMapLine(unsigned long address);//获取指定内存地址的Maps映射行 +char* getMapLineMemoryAreaName(const char* mapLine);//获取Maps映射行所在内存区域名称 +char* getMemoryAreaIdName(int memid);//获取指定内存id的内存名称 +char* getMemoryAreaName();//获取当前内存名称 +char* getDataTypeName(int typeId);//获取指定数据类型id的数据类型名称 + +//完全需要ROOT权限的操作 +//PS:告诉一下菜鸟,这些操作涉及到跨进程和系统操作,所以必须完全ROOT,直装也没用 +//--kill-- +int killProcess_Root(const char* packageName); // 杀掉指定包名的进程 (此方法对于执行者自身进程无需Root) +int stopProcess_Root(const char* packageName); // 暂停指定包名的进程 (此方法对于执行者自身进程无需Root) +int resumeProcess_Root(const char* packageName); // 恢复被暂停的指定包名的进程 (此方法对于执行者自身进程无需Root) +void killAllInotify_Root(); // 杀掉所有inotify监视器,防止游戏监视文件变化 +int killGG_Root(); // 杀掉GG修改器 +int killXscript_Root(); // 杀掉XS脚本 +//--Other-- +int rebootsystem_Root(); // 重启手机 +int installapk_Root(const char* apkPackagePath); // 静默安装 指定路径的APK安装包 +int uninstallapk_Root(const char* packageName); // 静默卸载 指定包名的APK软件 +int Cmd(const char* command);//执行命令 +int Cmd_Root(const char* command);//执行超级命令 + +//-内部耗时操作 +//void __MemorySearch__(const char* value, int type);//内存搜索 +//void __MemorySearchRange__(const char* value, int type);//范围内存搜索 +//void __MemorySearchUnited__(const char* value, int type);//联合内存搜索 +//void __ImproveOffset__(const char* value, int type, unsigned long offset);//偏移改善 +//void __ImproveOffsetRange__(const char* value, int type, unsigned long offset);//偏移范围改善 +//void __ImproveOffsetUnited__(const char* value, int type, unsigned long offset);//偏移联合改善 +//void __ImproveValue__(const char* value, int type);//改善 + +/// +/// 内存数据项 +/// +struct Item { + char* value;//值 + unsigned long addr;//地址 + int type; //类型 +}; + +/// +/// 联合搜索项 +/// +struct Federated { + char* value;//搜索值 + int type;//类型 + bool isRange = false;//是否为范围值 例1~20 + char minValue[64 + 2];//最小值(范围值) + char maxValue[64 + 2];//最大值(范围值) + /// + /// 构造 + /// + /// 搜索值 + /// 默认类型:如果值没有+类型字母符则使用此默认类型 + Federated(const char* v, int defType) { + //初始化类型 + if (strstr(v, U_dword) != nullptr || strstr(v, U_DWORD) != nullptr) { + type = TYPE_DWORD; + } + else if (strstr(v, U_float) != nullptr || strstr(v, U_FLOAT) != nullptr) { + type = TYPE_FLOAT; + } + else if (strstr(v, U_double) != nullptr || strstr(v, U_DOUBLE) != nullptr) { + type = TYPE_DOUBLE; + } + else if (strstr(v, U_word) != nullptr || strstr(v, U_WORD) != nullptr) { + type = TYPE_WORD; + } + else if (strstr(v, U_byte) != nullptr || strstr(v, U_BYTE) != nullptr) { + type = TYPE_BYTE; + } + else if (strstr(v, U_qword) != nullptr || strstr(v, U_QWORD) != nullptr) { + type = TYPE_QWORD; + } + else { + type = defType; + } + + //初始化值 + value = strdup(v); + + //去除值中的类型字母符 + int j = 0; //用于跟踪新的字符串索引 + for (int i = 0; value[i] != '\0'; i++) { + //检查当前字符是否为字母 + if (!isalpha(value[i])) { + //如果不是字母,则将其放到前面 + value[j] = value[i]; + j++; + } + } + value[j] = '\0'; //添加字符串结束符 + + //如果是范围值 [这里不要使用strtok来获取 因为如果外部正在使用strtok来初始化时这将影响到外部strtok的分割] + char* start = strstr(value, R_SEPARATE); + if (start != NULL) { + strncpy(minValue, value, start - value); //从开头到分隔符的部分为最小值 + minValue[start - value] = '\0'; //最小值最后的位置添加字符串结束符 + strcpy(maxValue, start + 1); //从分隔符后一个字符开始为最大值 + isRange = true; + } + } + +}; + +/// +/// 内存保护 +/// +struct Protection { + unsigned long addr;//地址 +}; + +///// +///// 内存搜索 +///// +///// 搜索值 +///// 搜索类型 +//void MemorySearch(const char* value, int type) { +// std::thread t([=]() { +// // 加锁,确保在访问 outcomeList 时是安全的 +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __MemorySearch__(value, type); // 假设 __MemorySearch__ 函数会操作 outcomeList +// }); +// t.detach(); +//} +// +///// +///// 内存搜索某个范围区域内的所有值 +///// +///// 范围值 格式:10~20 +///// 搜索类型 +//void MemorySearchRange(const char* value, int type) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __MemorySearchRange__(value, type); +// }); +// t.detach(); +//} +// +///// +///// 联合内存搜索 [注意:附近范围某些情况可能会比GG多4~8个字节] +///// +///// 联合搜索值 格式:值1;值2;值3;n个值:附近范围 +///// 默认联合搜索类型 +//void MemorySearchUnited(const char* value, int type) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __MemorySearchUnited__(value, type); +// }); +// t.detach(); +//} +// +///// +///// 从当前搜索结果中 筛选结果附近指定偏移处具有指定特征值的结果 +///// +///// 数据附近特征值 +///// 特征值数据类型 +///// 特征值相对主数据的偏移量 +//void ImproveOffset(const char* value, int type, unsigned long offset) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __ImproveOffset__(value, type, offset); +// }); +// t.detach(); +//} +// +///// +///// 从当前搜索结果中 筛选指定偏移处的值在这个范围内的结果 +///// +///// 范围值[格式:最小~最大] +///// 数据类型 +//void ImproveOffsetRange(const char* value, int type, unsigned long offset) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __ImproveOffsetRange__(value, type, offset); +// }); +// t.detach(); +//} +// +///// +///// 从当前搜索结果中 筛选指定偏移处的值为联合值中的某一个值的结果 +///// +///// 联合筛选值 +///// 默认类型 +//void ImproveOffsetUnited(const char* value, int type, unsigned long offset) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __ImproveOffsetUnited__(value, type, offset); +// }); +// t.detach(); +//} +// +///// +///// 从当前搜索结果中 直接改善 [支持范围改善和联合改善] +///// +///// 改善值 +///// 默认类型 +//void ImproveValue(const char* value, int type) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __ImproveValue__(value, type); +// }); +// t.detach(); +//} + +/// +/// 通过包名获取进程ID +/// +/// 进程APK包名 +/// 进程ID +int getPID(const char* packageName) +{ + int id = -1; // 进程ID,初始化为-1,表示未找到 + DIR* dir; // 目录流指针 + FILE* fp; // 文件指针 + char filename[64]; // 存储/proc/[pid]/cmdline路径 + char cmdline[64]; // 存储进程的命令行信息 + struct dirent* entry; // 目录项结构体,用于存储目录中的条目 + + dir = opendir("/proc"); // 打开/proc目录 + if (dir != NULL) { + while ((entry = readdir(dir)) != NULL) // 遍历/proc目录下的每一个条目 + { + id = atoi(entry->d_name); // 将条目名转换为进程ID + if (id >= 0) // 过滤非进程ID的条目 + { + sprintf(filename, "/proc/%d/cmdline", id); // 生成进程命令行文件路径 + fp = fopen(filename, "r"); // 打开命令行文件 + if (fp != NULL) + { + fgets(cmdline, sizeof(cmdline), fp); // 读取命令行信息 + fclose(fp); // 关闭文件 + if (strcmp(packageName, cmdline) == 0) // 比较包名与命令行信息 + { + closedir(dir); // 关闭目录 + return id;//找到了 + } + } + } + } + closedir(dir); // 关闭目录 + } + return -1; // 未找到进程,返回-1 +} + +/// +/// 设置包名,函数内部将获取该包名的进程ID方便之后操作 +/// +/// 进程APK包名 +/// 进程ID +int setPackageName(const char* packageName) +{ + pid = getPID(packageName); + if (pid != -1) { + sprintf(memPath, "/proc/%d/mem", pid);//初始化构造mem内存文件路径 + sprintf(mapsPath, "/proc/%d/maps", pid);//初始化构造maps内存文件路径 + isInit = true;//进行了初始化 + packName = strdup(packageName);//设置包名 + //outcomeList.reserve(100000000); // 预分配足够的内存 + } + return pid; +} + +/// +/// 设置安全写入的启用状态 +/// +/// 状态 +void setIsSecureWrites(bool sw) { + isSecureWrites = sw; +} + + + + + + +/// +/// 获取动态共享库的基址(起始地址) +/// +/// 动态共享库名称(后缀.so文件) +/// 基址头类型 +/// 基地址 +unsigned long getModuleBaseAddr(const char* module_name, int headType) +{ + if (!isInit) { + //未进行初始化 + return 0; + } + + //存储模块名称 + char* mod_name = strdup(module_name); //复制字符串 + if (mod_name == NULL) { + perror("strdup failed"); + return 0; + } + //检测如果包含:bss则去除 + char* pos = strstr(mod_name, ":bss"); + if (pos != NULL) { + //如果找到bss + *pos = '\0'; //将:bss换成字符串中断符进行截断 + } + FILE* fp; //文件指针 + unsigned long start = 0;//存储获取到的模块的起始地址 + unsigned long end = 0;//存储获取到的模块的结束地址 + char line[1024]; //存储读取的行 + bool cb = false; //是否开始查询bss + bool isFoundIt = false;//是否找到 + fp = fopen(mapsPath, "r"); + if (fp != NULL) + { + //逐行读取文件 + while (fgets(line, sizeof(line), fp)) + { + if (isMapsMemArea) { + //对于自定义内存区域 + if (strstr(line, memoryMaps)) { + //提取起始地址和结束地址 + sscanf(line, "%lx-%lx", &start, &end); + break; + } + } + else { + switch (headType) { + case HEAD_XA: + { + //查找行中是否包含模块名 + if (strstr(line, mod_name) && BCMAPSFLAG(line, RANGE_CODE_APP)) + { + //提取起始地址和结束地址 + sscanf(line, "%lx-%lx", &start, &end); + + //转换特殊地址 + if (start == 0x8000) { + start = 0; + } + isFoundIt = true;//找到了 + } + } + break; + case HEAD_CD://由于cd的结束地址是cb的起始地址 所以要先找到cb的起始地址 因此这里使用贯穿 + case HEAD_CB: + { + //找到模块名之后才开始查询bss + if (strstr(line, mod_name) && BCMAPSFLAG(line, RANGE_CODE_APP)) + { + cb = true; + } + if (cb) + { + if (BCMAPSFLAG(line, RANGE_C_BSS)) + { + //提取起始地址和结束地址 + sscanf(line, "%lx-%lx", &start, &end); + //如果是cb则直接找到 + if (headType == HEAD_CB) { + isFoundIt = true;//找到了 + break; + } + //如果是cd则开始查cd + if (headType == HEAD_CD) { + //将cb起始地址格式化为结束地址作为cd的筛选条件 + char str[100]; + sprintf(str, "-%lx", start); + + //重置文件指针到文件的开始位置 + fseek(fp, 0, SEEK_SET); + //重新逐行读取文件 + while (fgets(line, sizeof(line), fp)) { + if (strstr(line, str)) + { + //提取起始地址和结束地址 + sscanf(line, "%lx-%lx", &start, &end); + isFoundIt = true;//找到了 + break; + } + } + //重置文件指针到文件的开始位置 + fseek(fp, 0, SEEK_SET); + } + } + } + } + break; + } + //检查是否找到 + if (isFoundIt) { + break;//跳出循环 + } + } + + } + //关闭文件 + fclose(fp); + } + //释放模块字符串 + free(mod_name); + // 返回模块的基地址 + return start; +} +/// +/// 跳转到指定内存地址的指针 +/// +/// 内存地址 +// 要读取的字节数 +/// 指针地址 +unsigned long jump(unsigned long addr,int count) +{ + int fd = open(memPath, O_RDONLY); + if (fd >= 0) { + unsigned long pAddr=0; + ssize_t r = pread64(fd, &pAddr, count, addr); + if(r<0){ + pAddr = 0; + } + close(fd); + pAddr &= 0xFFFFFFFFFFFF; + return pAddr; + } + return 0; +} +/// +/// 跳转到指定内存地址的指针【32位】 +/// +/// 内存地址 +/// 指针地址 +unsigned long jump32(unsigned long addr) +{ + return jump(addr,4);//读取4字节 +} +/// +/// 跳转到指定内存地址的指针【64位】 +/// +/// 内存地址 +/// 指针地址 +unsigned long jump64(unsigned long addr) +{ + return jump(addr,8);//读取8字节 +} + + +/// +/// 设置指定内存地址指向的值 +/// +/// 设置的值 +/// 内存地址 +/// 数据类型 +/// 是否冻结 +/// 设置成功与否 +int setMemoryAddrValue(const char* value, unsigned long addr, int type, bool isFree,bool isSecure) +{ +int pageSize = getpagesize(); +void* addrToProtect; +unsigned long alignedAddr; + if (!isInit) { + //未进行初始化 + return -1; + } + + if(isSecure){ + addrToProtect = (void*)(addr); + + alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1);} + //是否冻结修改 + if (isFree) { + addFreezeItem(value, addr, type);//添加一个冻结修改项目 + startAllFreeze();//开始冻结 + return 0; + } + else { + + int fd = open(memPath, O_RDWR | O_SYNC); + //打开maps文件 + FILE* maps = fopen(mapsPath, "r"); + if (fd >= 0 && maps) { + switch (type) { + case TYPE_DWORD: + { + + DWORD v = atoi(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(DWORD), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(FLOAT), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(value, NULL); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(DOUBLE), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(QWORD), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(WORD), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(BYTE), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + } + + + } + if (fd >= 0) { + close(fd); + } + + if (maps) { + fclose(maps); + } + removeFreezeItem(addr);//移除这个冻结修改项目(如果存在) + return 0; + } + + + return -1; +} + +/// +/// 获取指定内存地址的数据 +/// +/// 内存地址 +/// 数据类型 +/// 获取到的数据[指针记得用完调用free释放] +char* getMemoryAddrData(unsigned long addr, int type) +{ + if (!isInit) { + //未进行初始化 + return "NULL"; + } + + int fd = open(memPath, O_RDONLY); + if (fd >= 0) { + int size = -1; + void* buff; + char* value = "NULL"; + + switch (type) + { + case TYPE_DWORD: + { + size = sizeof(DWORD);//存储要读取的字节数 + buff = (void*)malloc(size);//分配一块内存来存储读取到的数据 + pread64(fd, buff, size, addr);//从mem文件指定内存地址读取数据到buff + DWORD v = *(DWORD*)buff;//解析获取到的数据 + int len = snprintf(NULL, 0, "%d", v);//获取数据的字符长度 + value = (char*)malloc(len + 1);//字符串动态分配足够内存来存储数据 确保能足够存储数据的字符数量 + sprintf(value, "%d", v);//将数据格式化为字符串 + } + break; + case TYPE_FLOAT: + { + size = sizeof(FLOAT); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + FLOAT v = *(FLOAT*)buff; + int len = snprintf(NULL, 0, "%f", v); + value = (char*)malloc(len + 1); + sprintf(value, "%f", v); + //检测是否需要使用科学记数法来格式化 + bool isScience = true; + for (int i = 0; i < len; i++) { + if (value[i] == '.' || value[i] == '-') { + continue; + } + if (value[i] != '0') { + isScience = false; + } + } + if (isScience) { + sprintf(value, "%.8e", v); + } + if (strstr(value, "nan")) { + value = "NaN"; + } + } + break; + case TYPE_DOUBLE: + { + size = sizeof(DOUBLE); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + DOUBLE v = *(DOUBLE*)buff; + int len = snprintf(NULL, 0, "%f", v); + value = (char*)malloc(len + 1); + sprintf(value, "%f", v); + //检测是否需要使用科学记数法来格式化 + bool isScience = true; + if (len < 20) { + for (int i = 0; i < len; i++) { + if (value[i] == '.' || value[i] == '-') { + continue; + } + if (value[i] != '0') { + isScience = false; + } + } + } + if (isScience) { + sprintf(value, "%.8e", v); + } + if (strstr(value, "nan")) { + value = "NaN"; + } + } + break; + case TYPE_QWORD: + { + size = sizeof(QWORD); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + QWORD v = *(QWORD*)buff; + int len = snprintf(NULL, 0, "%lld", v); + value = (char*)malloc(len + 1); + sprintf(value, "%lld", v); + } + break; + case TYPE_WORD: + { + size = sizeof(WORD); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + WORD v = *(WORD*)buff; + int len = snprintf(NULL, 0, "%d", v); + value = (char*)malloc(len + 1); + sprintf(value, "%d", v); + } + break; + case TYPE_BYTE: + { + size = sizeof(BYTE); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + BYTE v = *(BYTE*)buff; + int len = snprintf(NULL, 0, "%d", v); + value = (char*)malloc(len + 1); + sprintf(value, "%d", v); + } + break; + } + + close(fd); + if (buff != NULL) { + free(buff); + } + return value; + } + return "NULL"; +} + + +/// +/// 设置要搜索的内存区域,初始化内存区域方便之后内存搜索 +/// +/// 内存区域 +void setMemoryArea(int memoryArea) +{ + memory = memoryArea; + isMapsMemArea = false; +} +/// +/// 设置自定义内存区域 好处:能精准找到想要的数据,并且搜索速度直接提升100倍 坏处:需要自己去找数据所在的maps内存段 示例:setMemoryArea("/apex/com.android.tethering/lib64/libframework-connectivity-jni.so"); +/// +/// maps内存段 +void setMemoryArea(const char* memoryArea) +{ + memoryMaps = strdup(memoryArea); + isMapsMemArea = true; +} +/// +/// 内存搜索 +/// +/// 搜索值 +/// 搜索类型 +/// 搜索结果列表 +vector < unsigned long > MemorySearch(const char* value, int type) +{ +if(getFreezeNum()>0){ +for(int i=0;i0){ + for(int i=0;i= 0 && maps) + { + + //清空搜索结果列表 + //clearResultList(); + + char mapLine[1024]; //用于存储每行读取到的信息 + unsigned long start; //存储内存起始地址 + unsigned long end; //存储内存结束地址 + //逐行读取maps文件每行信息 + while (fgets(mapLine, sizeof(mapLine), maps)) + { + //如果当前行匹配内存标志则进行搜索 + if (BCMAPSFLAG(mapLine, memory)) + { + //从该行中解析出内存区域的起始和结束地址 + sscanf(mapLine, "%lx-%lx", &start, &end); + int size = end - start; //计算内存区域的大小 + void* buf = (void*)malloc(size);//存储指向起始地址的指针 + int ret = pread64(mem, buf, size, start);//buf指向起始地址 + switch (type) + { + case TYPE_DWORD: + { + DWORD v = atoi(value);//存储要搜索的数值 + int increment = sizeof(DWORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(DWORD*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(value); + int increment = sizeof(FLOAT);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(FLOAT*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(value, NULL); + //DOUBLE v = atof(value); + int increment = sizeof(DOUBLE);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(DOUBLE*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(value); + int increment = sizeof(QWORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(QWORD*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(value); + int increment = sizeof(WORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(WORD*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(value); + int increment = sizeof(BYTE);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(BYTE*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + } + if (buf != NULL) { + free(buf); + } + } + } + } + if (mem >= 0) { + close(mem); + } + + if (maps) { + fclose(maps); + } + } + return outcomeList; +} + +/// +/// 内存搜索某个范围区域内的所有值 +/// +/// 范围值 格式:10~20 +/// 搜索类型 +/// 搜索结果列表 +vector < unsigned long > MemorySearchRange(const char* value, int type) +{ +if(getFreezeNum()>0){ +for(int i=0;i0){ + for(int i=0;i= 0 && maps) + { + //清空搜索结果列表 + //clearResultList(); + //outcomeList.reserve(100000000); // 预分配足够的内存 + char mapLine[1024]; //用于存储每行读取到的信息 + unsigned long start; //存储内存起始地址 + unsigned long end; //存储内存结束地址 + char formatString[50]; //存储格式规则 + + //逐行读取maps每一行 + while (fgets(mapLine, sizeof(mapLine), maps)) + { + + //如果当前行匹配内存标志则进行搜索 + if (BCMAPSFLAG(mapLine, memory)) + { + //从该行中解析出内存区域的起始和结束地址 + sscanf(mapLine, "%lx-%lx", &start, &end); + int size = end - start; //计算内存区域的大小 + void* buf = (void*)malloc(size);//存储指向起始地址的指针 + int ret = pread64(mem, buf, size, start);//buf指向起始地址 + switch (type) + { + case TYPE_DWORD: + { + DWORD minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%d", R_SEPARATE, "%d"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(DWORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + DWORD v = *(DWORD*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index);//添加几千万以上大量数据时可能会影响性能 + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_FLOAT: + { + FLOAT minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%f", R_SEPARATE, "%f"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(FLOAT);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + FLOAT v = *(FLOAT*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_DOUBLE: + { + DOUBLE minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%f", R_SEPARATE, "%f"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(DOUBLE);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + DOUBLE v = *(DOUBLE*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_QWORD: + { + QWORD minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%lld", R_SEPARATE, "%lld"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(QWORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + QWORD v = *(QWORD*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_WORD: + { + WORD minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%d", R_SEPARATE, "%d"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(WORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + WORD v = *(WORD*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_BYTE: + { + BYTE minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%d", R_SEPARATE, "%d"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(BYTE);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + BYTE v = *(BYTE*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + } + if (buf != NULL) { + free(buf); + } + + } + } + } + if (mem >= 0) { + close(mem); + } + + if (maps) { + fclose(maps); + } + } + return outcomeList; +} + + + +/// +/// 联合内存搜索 [注意:附近范围某些情况可能会比GG多4~8个字节 比如对于1~2;5:50这种情况gg的联合范围搜索只能按顺序 而这里是不按顺序的 对于联合范围加上::按顺序搜索就和GG联合范围一致了] +/// +/// 联合搜索值 格式:值1;值2;值3;n个值:附近范围 (没有范围则使用默认范围 两个范围符::代表按顺序搜索) 示例:7F;2D;3E:30 或 7F;2D;3E(未设置范围则使用默认范围) 并且值也支持范围例如1~2;3:64 +/// 默认联合搜索类型:对于未加类型符的值将使用此类型 例如1D;2;3E中的2将使用此类型 +/// 搜索结果 +vector < unsigned long > MemorySearchUnited(const char* value, int type) { +if(getFreezeNum()>0){ +for(int i=0;i0){ + for(int i=0;i valueList; //存储分割出的所有数值的列表 + //获取第一个分割部分 + const char* token = strtok(valueCopy, U_SEPARATE); + //逐个获取剩余的分割部分 + while (token != NULL) { + valueList.emplace_back(token, type); //保存分割出的值 + token = strtok(NULL, U_SEPARATE); // 获取下一个分割部分 + } + + //开始联合搜索 + if (!valueList.empty()) { + ///先搜第一个值的内存地址 作为起始地址 [如果第一个值是范围值内部将自动进行范围搜索这里无需判断] + MemorySearch(valueList[0].value, valueList[0].type); + //搜索剩余值 + //打开mem内存文件 + int mem = open(memPath, O_RDONLY); + if (mem >= 0) { + vector < unsigned long >offsetFilterResults; + for (int i = 0; i < outcomeList.size(); i++) + { + vector < Item > results;//存储当前起始地址附近找到的值列表 + //开始查找当前起始地址附近的值 + for (int j = 0; j < valueList.size(); j++) + { + switch (valueList[j].type) + { + case TYPE_DWORD: + { + DWORD v; + DWORD minv; + DWORD maxv; + if (valueList[j].isRange) { + minv = atoi(valueList[j].minValue); + maxv = atoi(valueList[j].maxValue); + } + else { + v = atoi(valueList[j].value); + } + int size = sizeof(DWORD); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + DWORD eV = *(DWORD*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + + } + offset += size; + } + free(buf); + } + break; + case TYPE_FLOAT: + { + FLOAT v; + FLOAT minv; + FLOAT maxv; + if (valueList[j].isRange) { + minv = atof(valueList[j].minValue); + maxv = atof(valueList[j].maxValue); + } + else { + v = atof(valueList[j].value); + } + int size = sizeof(FLOAT); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + FLOAT eV = *(FLOAT*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + case TYPE_DOUBLE: + { + DOUBLE v; + DOUBLE minv; + DOUBLE maxv; + if (valueList[j].isRange) { + minv = strtod(valueList[j].minValue, NULL); + maxv = strtod(valueList[j].maxValue, NULL); + } + else { + v = strtod(valueList[j].value, NULL); + } + int size = sizeof(DOUBLE); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + DOUBLE eV = *(DOUBLE*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + case TYPE_QWORD: + { + QWORD v; + QWORD minv; + QWORD maxv; + if (valueList[j].isRange) { + minv = atoll(valueList[j].minValue); + maxv = atoll(valueList[j].maxValue); + } + else { + v = atoll(valueList[j].value); + } + int size = sizeof(QWORD); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + QWORD eV = *(QWORD*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + case TYPE_WORD: + { + WORD v; + WORD minv; + WORD maxv; + if (valueList[j].isRange) { + minv = (WORD)atoi(valueList[j].minValue); + maxv = (WORD)atoi(valueList[j].maxValue); + } + else { + v = (WORD)atoi(valueList[j].value); + } + int size = sizeof(WORD); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + WORD eV = *(WORD*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + case TYPE_BYTE: + { + BYTE v; + BYTE minv; + BYTE maxv; + if (valueList[j].isRange) { + minv = (BYTE)atoi(valueList[j].minValue); + maxv = (BYTE)atoi(valueList[j].maxValue); + } + else { + v = (BYTE)atoi(valueList[j].value); + } + int size = sizeof(BYTE); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + BYTE eV = *(BYTE*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + } + } + + if (results.size() >= valueList.size()) { + //检查当前找到的附近值向量中是否包含搜索值向量中的所有元素 (包含所有才添加到结果) + bool isAdd = true; + for (int i = 0; i < valueList.size(); i++) + { + bool found = false; + for (int j = 0; j < results.size(); j++) + { + if (strcmp(results[j].value, valueList[i].value) == 0) { + found = true; + break; + } + } + if (!found) { + isAdd = false; + break; + } + } + + if (isAdd) { + for (int h = 0; h < results.size(); h++) + { + //防止重复添加 + if (find(offsetFilterResults.begin(), offsetFilterResults.end(), results[h].addr) == offsetFilterResults.end()) { + //if (labs(outcomeList[i] - results[h]) <= unitedRange) { + offsetFilterResults.push_back(results[h].addr); + //} + } + } + } + } + } + + close(mem); + //筛选完成则清空最终筛选结果列表 + outcomeList.clear(); + //将新筛选出的结果列表添加进最终筛选结果列表 + for (int i = 0; i < offsetFilterResults.size(); i++) + { + outcomeList.push_back(offsetFilterResults[i]); + } + //升序排序结果 + sort(outcomeList.begin(), outcomeList.end()); + } + } + free(valueCopy); //释放副本内存 + } + return outcomeList; +} + + + +/// +/// 从当前搜索结果中 筛选结果附近指定偏移处具有指定特征值的结果 [支持范围改善,联合改善] +/// +/// 数据附近特征值 +/// 特征值数据类型 +/// 特征值相对主数据的偏移量 +/// 最终筛选结果列表 +vector < unsigned long > ImproveOffset(const char* value, int type, unsigned long offset) +{ + if (isInit) { + //如果包含分隔符则使用偏移联合改善 + if (strstr(value, U_SEPARATE)) { + return ImproveOffsetUnited(value, type, offset); + } + //如果包含范围则使用偏移范围改善 + if (strstr(value, R_SEPARATE) && !strstr(value, U_SEPARATE)) { + return ImproveOffsetRange(value, type, offset); + } + vector < unsigned long >offsetFilterResults;//临时筛选结果列表 - 临时存储当前偏移筛选出的附近拥有特征值的数据 + int fd = open(memPath, O_RDONLY); + if (fd >= 0) + { + switch (type) + { + case TYPE_DWORD: + { + DWORD v = atoi(value); + int size = sizeof(DWORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(DWORD*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(value); + int size = sizeof(FLOAT); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(FLOAT*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(value, NULL); + int size = sizeof(DOUBLE); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(DOUBLE*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(value); + int size = sizeof(QWORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(QWORD*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(value); + int size = sizeof(WORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(WORD*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(value); + int size = sizeof(BYTE); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(BYTE*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + } + close(fd); + //筛选完成则清空最终筛选结果列表 + outcomeList.clear(); + //将新筛选出的结果列表添加进最终筛选结果列表 + for (int i = 0; i < offsetFilterResults.size(); i++) + { + outcomeList.push_back(offsetFilterResults[i]); + } + } + } + return outcomeList; +} + +/// +/// 从当前搜索结果中 筛选指定偏移处的值在这个范围内的结果 [偏移范围改善] 适用于:某些特征码会变化但是只会在一个范围之内变化时 比如特征码始终为1或2或3时 可以使用偏移范围改善使用1~3即可 +/// +/// 范围值[格式:最小~最大 例如1~20] +/// 数据类型 +/// +vector < unsigned long > ImproveOffsetRange(const char* value, int type, unsigned long offset) { + if (isInit) { + char minValue[64 + 2]; + char maxValue[64 + 2]; + const char* start = strstr(value, R_SEPARATE); + if (start != NULL) { + strncpy(minValue, value, start - value); //从开头到分隔符的部分为最小值 + minValue[start - value] = '\0'; //最小值最后的位置添加字符串结束符 + strcpy(maxValue, start + 1); //从分隔符后一个字符开始为最大值 + } + vector < unsigned long >offsetFilterResults;//临时筛选结果列表 - 临时存储当前偏移筛选出的附近拥有特征值的数据 + int fd = open(memPath, O_RDONLY); + if (fd >= 0) + { + switch (type) + { + case TYPE_DWORD: + { + DWORD minv = atoi(minValue); + DWORD maxv = atoi(maxValue); + int size = sizeof(DWORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + DWORD bV = *(DWORD*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_FLOAT: + { + FLOAT minv = atof(minValue); + FLOAT maxv = atof(maxValue); + int size = sizeof(FLOAT); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + FLOAT bV = *(FLOAT*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_DOUBLE: + { + DOUBLE minv = strtod(minValue, NULL); + DOUBLE maxv = strtod(maxValue, NULL); + int size = sizeof(DOUBLE); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + DOUBLE bV = *(DOUBLE*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_QWORD: + { + QWORD minv = atoll(minValue); + QWORD maxv = atoll(maxValue); + int size = sizeof(QWORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + QWORD bV = *(QWORD*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_WORD: + { + WORD minv = (WORD)atoi(minValue); + WORD maxv = (WORD)atoi(maxValue); + int size = sizeof(WORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + WORD bV = *(WORD*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_BYTE: + { + BYTE minv = (BYTE)atoi(minValue); + BYTE maxv = (BYTE)atoi(maxValue); + int size = sizeof(BYTE); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + BYTE bV = *(BYTE*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + } + close(fd); + //筛选完成则清空最终筛选结果列表 + outcomeList.clear(); + //将新筛选出的结果列表添加进最终筛选结果列表 + for (int i = 0; i < offsetFilterResults.size(); i++) + { + outcomeList.push_back(offsetFilterResults[i]); + } + } + } + return outcomeList; + +} + +/// +/// 从当前搜索结果中 筛选指定偏移处的值为联合值中的某一个值的结果 [偏移联合改善] 适用于:某些特征码会变化但是永远只会变为那几个固定值的情况 比如只会变化为22或15或27时可以使用偏移联合改善22;15;27 +/// +/// 联合筛选值:[格式:值1;值2;值3;n个值 示例:7F;2D;3E 并且值也支持范围例如1~2;3 注:改善不支持顺序改善和区间范围] +/// 默认类型:对于未将类型符的值使用此类型 例如1D;2;3E中的2将使用此类型 +/// +vector < unsigned long > ImproveOffsetUnited(const char* value, int type, unsigned long offset) { + if (isInit) { + //LOGD("联合改善调试", "start"); + char* valueCopy = strdup(value);//创建副本内存因为之后要进行修改传入的字符串 + + //获取联合改善数值到列表 + vector < Federated > valueList; //存储分割出的所有数值的列表 + //获取第一个分割部分 + const char* token = strtok(valueCopy, U_SEPARATE); + //逐个获取剩余的分割部分 + while (token != NULL) { + valueList.emplace_back(token, type); //保存分割出的值 + token = strtok(NULL, U_SEPARATE); // 获取下一个分割部分 + } + + //开始联合改善 + if (!valueList.empty()) { + //打开mem内存文件 + int mem = open(memPath, O_RDONLY); + if (mem >= 0) { + vector < unsigned long >filterResults;//存储临时改善结果列表 + for (int i = 0; i < outcomeList.size(); i++) + { + for (int j = 0; j < valueList.size(); j++) + { + bool isF = false;//标记是否已找到 + switch (valueList[j].type) + { + case TYPE_DWORD: + { + int size = sizeof(DWORD); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + DWORD eV = *(DWORD*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + DWORD minv = atoi(valueList[j].minValue); + DWORD maxv = atoi(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + DWORD v = atoi(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_FLOAT: + { + int size = sizeof(FLOAT); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + FLOAT eV = *(FLOAT*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + FLOAT minv = atof(valueList[j].minValue); + FLOAT maxv = atof(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + FLOAT v = atof(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_DOUBLE: + { + int size = sizeof(DOUBLE); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + DOUBLE eV = *(DOUBLE*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + DOUBLE minv = strtod(valueList[j].minValue, NULL); + DOUBLE maxv = strtod(valueList[j].maxValue, NULL); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + DOUBLE v = strtod(valueList[j].value, NULL); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_QWORD: + { + int size = sizeof(QWORD); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + QWORD eV = *(QWORD*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + QWORD minv = atoll(valueList[j].minValue); + QWORD maxv = atoll(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + QWORD v = atoll(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_WORD: + { + int size = sizeof(WORD); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + WORD eV = *(WORD*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + WORD minv = (WORD)atoi(valueList[j].minValue); + WORD maxv = (WORD)atoi(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + WORD v = (WORD)atoi(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_BYTE: + { + int size = sizeof(BYTE); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + BYTE eV = *(BYTE*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + BYTE minv = (BYTE)atoi(valueList[j].minValue); + BYTE maxv = (BYTE)atoi(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + BYTE v = (BYTE)atoi(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + } + //找到则结束循环 开始匹配下一轮的值 + if (isF) { + break; + } + } + } + + close(mem); + //筛选完成则清空最终筛选结果列表 + outcomeList.clear(); + //将新筛选出的结果列表添加进最终筛选结果列表 + for (int i = 0; i < filterResults.size(); i++) + { + outcomeList.push_back(filterResults[i]); + } + //升序排序结果 + //sort(outcomeList.begin(), outcomeList.end()); + } + } + free(valueCopy); //释放副本内存 + } + return outcomeList; +} +/// +/// 从当前搜索结果中 直接改善 [支持范围改善和联合改善] +/// +/// 改善值 +/// 默认类型 +/// 结果 +vector < unsigned long > ImproveValue(const char* value, int type) { + return ImproveOffset(value, type, 0); +} +/// +/// 从最终所有筛选结果的指定偏移处进行写入数据 +/// +/// 写入的数据 +/// 写入数据类型 +/// 相对筛选结果处的偏移量 +/// 是否冻结写入 +/// 写入成功与否 +int MemoryOffsetWrite(const char* value, int type, unsigned long offset, bool isFree,bool isSecure) +{ + if (!isInit) { + //没有进行初始化 + return -1; + } + isSecureWrites=isSecure; + int pageSize = getpagesize(); + int fd = open(memPath, O_RDWR | O_SYNC); + //打开maps文件 + FILE* maps = fopen(mapsPath, "r"); + if (fd >= 0 && maps) + { + + for (int i = 0; i < outcomeList.size(); i++) { + if(isSecureWrites){ + MemoryProtect(outcomeList[i] + offset);} + if (isFree) { + + addFreezeItem(value, outcomeList[i] + offset, type); + startAllFreeze(); + } + else { + + switch (type) + { + case TYPE_DWORD: + { + DWORD v = atoi(value); + + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(DWORD), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(value); + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(FLOAT), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(value, NULL); + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(DOUBLE), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(value); + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(DOUBLE), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(value); + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(WORD), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(value); + + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(BYTE), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + } + + removeFreezeItem(outcomeList[i] + offset);//关闭冻结 + } + } + return 0; + } + if (fd >= 0) { + close(fd); + } + + if (maps) { + fclose(maps); + } + return -1;//内存写入成功 +} + +/// +/// 获取最终搜索结果数量 +/// +/// 最终搜索结果数量 +int getResultCount() +{ + return outcomeList.size(); +} + +/// +/// 获取最终搜索结果列表 +/// +/// 最终搜索结果列表 +vector < unsigned long > getResultList() +{ + return outcomeList; +} + +/// +/// 打印最终搜索结果列表到文件 +/// +/// 文件路径 +/// 成功与否 +int printResultListToFile(const char* filePath) +{ + FILE* memDebugFile = fopen(filePath, "a");//追加模式打开 + if (memDebugFile != NULL) { + struct timeval tv; + struct tm* tm_info; + char timeString[100]; + + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + + strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tm_info); + fprintf(memDebugFile, "\n\n\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "[LogName] 日志名称:内存搜索结果列表\n"); + fprintf(memDebugFile, "[ABI] 处理器:%s\n", ABI); + fprintf(memDebugFile, "[PackName] 进程包名:%s\n", packName); + fprintf(memDebugFile, "[PID] 进程ID:%d\n", pid); + fprintf(memDebugFile, "[PID] 搜索内存:%s\n", getMemoryAreaName()); + fprintf(memDebugFile, "[RCount] 搜索结果数量:%d\n", outcomeList.size()); + fprintf(memDebugFile, "[AddTime] 日志生成时间:%s.%ld\n", timeString, tv.tv_usec); + fprintf(memDebugFile, "[Source] 来源:ByteCat-MemTool ^O^\n"); + fprintf(memDebugFile, "ByteCat:以下数据仅用于内存分析和调试,请勿用于违法用途!\n"); + fprintf(memDebugFile, "ByteCat: The above data is only used for memory analysis and debugging, please do not use it for illegal purposes!\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "[Debug] Log format: Timestamp | Memory Area | Memory Address | DWORD Data | FLOAT Data | DOUBLE Data | WORD Data | BYTE Data | QWORD Data | Mem Map\n"); + fprintf(memDebugFile, "[调试] 日志格式: 时间戳 | 内存区域 | 内存地址 | DWORD类型数据 | FLOAT类型数据 | DOUBLE类型数据 | WORD类型数据 | BYTE类型数据 | QWORD类型数据 | 内存映射\n"); + for (int i = 0; i < outcomeList.size(); i++) + { + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tm_info); + char* mapLine = getMemoryAddrMapLine(outcomeList[i]); + fprintf(memDebugFile, "%s.%06ld 📍 内存区域:%s 内存地址:0x%lX D类型:%s F类型:%s E类型:%s W类型:%s B类型:%s Q类型:%s 📑 内存映射:%s\n", timeString, tv.tv_usec, + getMapLineMemoryAreaName(mapLine), + outcomeList[i], + getMemoryAddrData(outcomeList[i], TYPE_DWORD), + getMemoryAddrData(outcomeList[i], TYPE_FLOAT), + getMemoryAddrData(outcomeList[i], TYPE_DOUBLE), + getMemoryAddrData(outcomeList[i], TYPE_WORD), + getMemoryAddrData(outcomeList[i], TYPE_BYTE), + getMemoryAddrData(outcomeList[i], TYPE_QWORD), + mapLine); + } + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "注:以上数据仅用于内存分析和调试,请勿用于违法用途!\n"); + fprintf(memDebugFile, "Note: The above data is only used for memory analysis and debugging, please do not use it for illegal purposes!\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fclose(memDebugFile); + return 0; + } + + return -1; +} + +/// +/// 清空最终搜索结果列表 +/// +int clearResultList() +{ + if (outcomeList.empty()) { + //空列表不做操作 + return -1; + } + //清空搜索结果列表 + outcomeList.clear(); + // 释放内存 + std::vector().swap(outcomeList); + return 0; +} + +/// +/// 内存保护二次修改 +/// +void MemoryProtect(unsigned long addr){ +Protection Memory; + Memory.addr = addr; + ProtectList.push_back(Memory); +} +/// +/// 获取保护项目数量 +/// +/// 数量 +int getProtectionNum() { + return ProtectList.size(); +} +/// +/// 设置冻结修改延迟【毫秒】 +/// +/// 延迟[MS] +void setFreezeDelayMs(uint32_t delay) { + freezeDelay = delay; +} + +/// +/// 获取冻结修改项目列表 +/// +/// 冻结修改项目列表 +vector < Item > getFreezeList() { + return FreezeList; +} + +/// +/// 获取冻结修改项目数量 +/// +/// 数量 +int getFreezeNum() { + return FreezeList.size(); +} + +/// +/// 添加一个冻结修改项目 +/// +/// 修改值 +/// 内存地址 +/// 数据类型 +int addFreezeItem(const char* value, unsigned long addr, int type) +{ + //检查冻结修改项目列表是否已经存在此内存地址,防止重复添加冻结修改项目 + for (int i = 0; i < FreezeList.size(); i++) + { + if (addr == FreezeList[i].addr) + { + return -1; + } + } + Item table; + table.value = strdup(value); + table.addr = addr; + table.type = type; + FreezeList.push_back(table); + return 0; +} + +/// +/// 移除一个冻结修改项目 +/// +/// 内存地址 +int removeFreezeItem(unsigned long addr) +{ + for (int i = 0; i < FreezeList.size(); i++) + { + if (addr == FreezeList[i].addr) + { + FreezeList.erase(FreezeList.begin() + i); + return 0; + } + } + return -1; +} + +/// +/// 移除所有冻结修改项目 +/// +int removeAllFreezeItem() { + if (FreezeList.empty()) { + //空列表不做操作 + return -1; + } + // 清除所有数据 + FreezeList.clear(); + // 释放内存 + std::vector().swap(FreezeList); + return 0; +} + +/// +/// 冻结循环修改线程 +/// +/// +/// +void* freezeThread(void* arg) +{ + unsigned long alignedAddr; + void* addrToProtect; + for (;;) + { + if (isInit) { + //如果需要结束冻结或者冻结列表没有冻结项目则结束 + if (!isFreeze || FreezeList.size() == 0) + { + stopAllFreeze(); + break; + } + //每轮冻结才打开mem为了提升性能而不是在每次修改时都打开mem 避免频繁IO + int fd = open(memPath, O_RDWR | O_SYNC); + if (fd >= 0) { + //遍历 内存修改 冻结列表的所有项目 + for (int i = 0; i < FreezeList.size(); i++) + { + int pageSize = getpagesize(); +if(isSecureWrites){ +addrToProtect = (void*)(FreezeList[i].addr); +alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); } + + + switch (FreezeList[i].type) + { + + case TYPE_DWORD: + { + DWORD v = atoi(FreezeList[i].value); + + pwrite64(fd, &v, sizeof(DWORD), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(FreezeList[i].value); + + + pwrite64(fd, &v, sizeof(FLOAT), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize,PROT_WRITE | PROT_EXEC); + } + + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(FreezeList[i].value, NULL); + + + pwrite64(fd, &v, sizeof(DOUBLE), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize,PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(FreezeList[i].value); + + + pwrite64(fd, &v, sizeof(QWORD), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize,PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(FreezeList[i].value); + + + pwrite64(fd, &v, sizeof(WORD), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(FreezeList[i].value); + + + pwrite64(fd, &v, sizeof(BYTE), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize,PROT_WRITE | PROT_EXEC); + } + break; + } + } + close(fd); + } + //延迟 + if (freezeDelay != 0) { + usleep(freezeDelay * 1000);//转换为微秒 + } + } + + } + return NULL; +} + +/// +/// 开始所有冻结修改项目 +/// +int startAllFreeze() +{ + if (!isInit) { + //没有进行初始化 + return -1; + } + if (!isFreeze) + { + //冻结列表有项目才开冻结线程 + if (FreezeList.size() > 0) + { + isFreeze = true;//正在冻结 + //开始启动冻结线程 + pthread_t t; + pthread_create(&t, NULL, freezeThread, NULL); + return 0; + } + } + return -1; +} + +/// +/// 停止所有冻结修改项目 +/// +int stopAllFreeze() +{ + if (isFreeze) + { + isFreeze = false; + return 0; + } + return -1; +} + +/// +/// 打印冻结列表到指定文件 +/// +/// 文件绝对路径 +/// 成功与否 +int printFreezeListToFile(const char* filePath) +{ + FILE* memDebugFile = fopen(filePath, "a");//追加模式打开 + if (memDebugFile != NULL) { + struct timeval tv; + struct tm* tm_info; + char timeString[100]; + + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + + strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tm_info); + fprintf(memDebugFile, "\n\n\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "[LogName] 日志名称:冻结修改列表\n"); + fprintf(memDebugFile, "[ABI] 处理器:%s\n", ABI); + fprintf(memDebugFile, "[PackName] 进程包名:%s\n", packName); + fprintf(memDebugFile, "[PID] 进程ID:%d\n", pid); + fprintf(memDebugFile, "[RCount] 冻结修改数量:%d\n", FreezeList.size()); + fprintf(memDebugFile, "[AddTime] 日志生成时间:%s.%ld\n", timeString, tv.tv_usec); + fprintf(memDebugFile, "[Source] 来源:ByteCat-MemTool ^O^\n"); + fprintf(memDebugFile, "ByteCat:以下数据仅用于内存分析和调试,请勿用于违法用途!\n"); + fprintf(memDebugFile, "ByteCat: The above data is only used for memory analysis and debugging, please do not use it for illegal purposes!\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "[Debug] Log format: [❄ Freeze info] Timestamp | Memory Area | Memory Address | DWORD Data | FLOAT Data | DOUBLE Data | WORD Data | BYTE Data | QWORD Data | Mem Map\n"); + fprintf(memDebugFile, "[调试] 日志格式: [❄ 冻结信息] 时间戳 | 内存区域 | 内存地址 | DWORD类型数据 | FLOAT类型数据 | DOUBLE类型数据 | WORD类型数据 | BYTE类型数据 | QWORD类型数据 | 内存映射\n"); + for (int i = 0; i < FreezeList.size(); i++) + { + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tm_info); + char* mapLine = getMemoryAddrMapLine(FreezeList[i].addr); + fprintf(memDebugFile, "%s.%06ld 【❄ 修改值:%s 修改类型:%s】 📍 内存区域:%s 内存地址:0x%lX D类型:%s F类型:%s E类型:%s W类型:%s B类型:%s Q类型:%s 📑 内存映射:%s\n", timeString, tv.tv_usec, + FreezeList[i].value, + getDataTypeName(FreezeList[i].type), + getMapLineMemoryAreaName(mapLine), + FreezeList[i].addr, + getMemoryAddrData(FreezeList[i].addr, TYPE_DWORD), + getMemoryAddrData(FreezeList[i].addr, TYPE_FLOAT), + getMemoryAddrData(FreezeList[i].addr, TYPE_DOUBLE), + getMemoryAddrData(FreezeList[i].addr, TYPE_WORD), + getMemoryAddrData(FreezeList[i].addr, TYPE_BYTE), + getMemoryAddrData(FreezeList[i].addr, TYPE_QWORD), + mapLine); + } + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "注:以上数据仅用于内存分析和调试,请勿用于违法用途!\n"); + fprintf(memDebugFile, "Note: The above data is only used for memory analysis and debugging, please do not use it for illegal purposes!\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fclose(memDebugFile); + return 0; + } + + return -1; +} + +/// +/// 获取指定内存地址的maps映射行 +/// +/// 内存地址 +/// maps映射行 +char* getMemoryAddrMapLine(unsigned long address) { + if (!isInit) { + return "NULL"; + } + //存储映射信息 + unsigned long start, end, offset; + char perms[5], dev[6], path[1024]; + int inode; + + FILE* file; //maps文件指针 + char line[4096]; //存储读取到的一行数据 + + file = fopen(mapsPath, "r"); + if (file) { + //逐行读取maps文件内容 + while (fgets(line, sizeof(line), file)) { + + sscanf(line, "%lx-%lx %4s %lx %5s %d %[^\n]", + &start, &end, perms, &offset, dev, &inode, path); + //如果给定的地址在当前行描述的内存区域范围内 + if (address >= start && address < end) { + fclose(file); // 关闭文件 + return line;//返回映射行 + } + } + fclose(file); // 关闭文件 + } + return "NULL"; +} + +/// +/// 获取Maps映射行所在内存区域名称 +/// +/// +/// 内存名称字符串 +char* getMapLineMemoryAreaName(const char* mapLine) { + //jh和j 模拟器cd和xa + + if (BCMAPSFLAG(mapLine, RANGE_C_HEAP)) { + return "C堆内存 [Ch: C++ heap]"; + } + if (BCMAPSFLAG(mapLine, RANGE_C_ALLOC)) { + return "C分配内存 [Ca: C++ alloc]"; + } + if (BCMAPSFLAG(mapLine, RANGE_C_BSS)) { + return "C未初始化数据 [Cb: C++ .bss]"; + } + if (BCMAPSFLAG(mapLine, RANGE_ANONYMOUS)) { + return "匿名内存 [A: Anonymous]"; + } + if (BCMAPSFLAG(mapLine, RANGE_STACK)) { + return "栈内存 [S: Stack]"; + } + if (BCMAPSFLAG(mapLine, RANGE_ASHMEM)) { + return "Android共享内存 [As: Ashmem]"; + } + if (BCMAPSFLAG(mapLine, RANGE_VIDEO)) { + //BCMEM_LOGI("此内存有错误"); + return "视频内存 [V: Video]"; + } + if (BCMAPSFLAG(mapLine, RANGE_B_BAD)) { + //BCMEM_LOGI("此内存有错误"); + return "错误内存 [B: Bad]"; + } + if (BCMAPSFLAG(mapLine, RANGE_CODE_SYSTEM)) { + return "系统代码 [Xs: Code system]"; + } + + //j内存和jh内存筛选特征相同 + /*if (BCMAPSFLAG(mapLine, RANGE_JAVA_HEAP)) { + return "Java虚拟机堆内存 [Jh: Java heap]"; + }*/ + if (BCMAPSFLAG(mapLine, RANGE_JAVA)) { + return "Java内存 [J: Java] 或 Java虚拟机堆内存 [Jh: Java heap]"; + } + + //cd和xa在模拟器可能错误 因此针对 +#if defined(__arm__) || defined(__aarch64__) //arm32和arm64架构 + if (BCMAPSFLAG(mapLine, RANGE_C_DATA)) { + return "C数据内存 [Cd: C++ .data]"; + } + if (BCMAPSFLAG(mapLine, RANGE_CODE_APP)) { + return "应用程序代码 [Xa: Code app]"; + } +#else//x86和x64架构 针对模拟器 + if (BCMAPSFLAG(mapLine, RANGE_C_DATA)) { + return "C数据内存 [Cd: C++ .data] 或 应用程序代码 [Xa: Code app]"; + } + if (BCMAPSFLAG(mapLine, RANGE_CODE_APP)) { + return "应用程序代码 [Xa: Code app]"; + } +#endif + + + //if (BCMAPSFLAG(mapLine, RANGE_OTHER)) { + // //BCMEM_LOGI("此内存有错误,无法完全排除"); + // return "其他内存 [O: Other]"; + //} + + //以上都不是则在O + return "其他内存 [O: Other]"; +} + + +/// +/// 获取指定id的内存名称 +/// +/// 内存id +/// 内存名称字符串 +char* getMemoryAreaIdName(int memid) { + if (memid == RANGE_ALL) { + return "所有内存 [ALL]"; + } + if (memid == RANGE_JAVA_HEAP) { + return "Java虚拟机堆内存 [Jh: Java heap]"; + } + if (memid == RANGE_C_HEAP) { + return "C堆内存 [Ch: C++ heap]"; + } + if (memid == RANGE_C_ALLOC) { + return "C分配内存 [Ca: C++ alloc]"; + } + if (memid == RANGE_C_DATA) { + return "C数据内存 [Cd: C++ .data]"; + } + if (memid == RANGE_C_BSS) { + return "C未初始化数据 [Cb: C++ .bss]"; + } + if (memid == RANGE_ANONYMOUS) { + return "匿名内存 [A: Anonymous]"; + } + if (memid == RANGE_JAVA) { + return "Java内存 [J: Java]"; + } + if (memid == RANGE_STACK) { + return "栈内存 [S: Stack]"; + } + if (memid == RANGE_ASHMEM) { + return "Android共享内存 [As: Ashmem]"; + } + if (memid == RANGE_VIDEO) { + //BCMEM_LOGI("此内存有错误"); + return "视频内存 [V: Video]"; + } + if (memid == RANGE_OTHER) { + //BCMEM_LOGI("此内存有错误,无法完全排除"); + return "其他内存 [O: Other]"; + } + if (memid == RANGE_B_BAD) { + //BCMEM_LOGI("此内存有错误"); + return "错误内存 [B: Bad]"; + } + if (memid == RANGE_CODE_APP) { + return "应用程序代码 [Xa: Code app]"; + } + if (memid == RANGE_CODE_SYSTEM) { + return "系统代码 [Xs: Code system]"; + } + + return "未知内存 [NULL]"; +} +/// +/// 获取当前内存名称 +/// +/// 内存名称字符串 +char* getMemoryAreaName() { + return getMemoryAreaIdName(memory); +} + +/// +/// 获取数据类型名称 +/// +/// 类型id +/// 类型名称字符串 +char* getDataTypeName(int typeId) { + switch (typeId) + { + case TYPE_DWORD: + { + return "DWORD-32位有符号整数 [D: int32_t]"; + } + break; + case TYPE_FLOAT: + { + return "FLOAT-单精度浮点数 [F: float]"; + } + break; + case TYPE_DOUBLE: + { + return "DOUBLE-双精度浮点数 [E: double]"; + } + break; + case TYPE_QWORD: + { + return "QWORD-64位有符号整数 [Q: int64_t]"; + } + break; + case TYPE_WORD: + { + return "WORD-有符号短整型 [W: signed short]"; + } + break; + case TYPE_BYTE: + { + return "BYTE-有符号字符 [B: signed char]"; + } + break; + default: + { + return "未知类型 [NULL]"; + } + break; + } +} + +/// +/// 杀掉指定包名的进程 +/// +/// 进程APK包名 +/// 成功与否 +int killProcess_Root(const char* packageName) +{ + int pid = getPID(packageName); //获取进程ID + if (pid == -1) + { + return -1; + } + + //SIGTERM信号杀死进程 + if (kill(pid, SIGTERM) == -1) { + return -1; + } + + return 0; //成功 +} + +/// +/// 暂停指定包名的进程 +/// +/// 进程包名 +/// 成功与否 +int stopProcess_Root(const char* packageName) { + int pid = getPID(packageName); + if (pid == -1) { + return -1; + } + + //SIGSTOP信号暂停进程 + if (kill(pid, SIGSTOP) == -1) { + return -1; + } + return 0; //成功 +} + +/// +/// 恢复被暂停的指定包名的进程 +/// +/// 进程包名 +/// 成功与否 +int resumeProcess_Root(const char* packageName) { + int pid = getPID(packageName); + if (pid == -1) { + return -1; + } + + //SIGCONT信号恢复被暂停的进程 + if (kill(pid, SIGCONT) == -1) { + return -1; + } + return 0; //成功 +} +/// +/// 杀死所有inotify,防止游戏监视文件变化 +/// +void killAllInotify_Root() +{ + //通过将内核inotify文件监视器的最大数量设置为0 这样就可以禁用所有inotify + system("echo 0 > /proc/sys/fs/inotify/max_user_watches"); +} + +/// +/// 杀死GG修改器进程 +/// +/// 杀死的进程数量 +int killGG_Root() +{ + DIR* dir = NULL; //指向目录流的指针 + DIR* dirGG = NULL; //指向子目录流的指针 + struct dirent* ptr = NULL; //目录项结构体,用于存储目录中的条目 + struct dirent* ptrGG = NULL; //目录项结构体,用于存储子目录中的条目 + char filepath[256]; //存储文件路径 + int num = 0;// 数量 + + dir = opendir("/data/data"); + if (dir != NULL) { + //检测data目录下每一个包名文件夹下是否为GG修改器 + while ((ptr = readdir(dir)) != NULL) + { + //跳过"."和".."目录和文件 + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0) || (ptr->d_type != DT_DIR)) { + continue; + } + + //生成当前包名的files文件夹的完整路径 + sprintf(filepath, "/data/data/%s/files", ptr->d_name); + dirGG = opendir(filepath); //打开files + if (dirGG != NULL) + { + while ((ptrGG = readdir(dirGG)) != NULL) + { + // 跳过"."和".."目录和文件 + if ((strcmp(ptrGG->d_name, ".") == 0) || (strcmp(ptrGG->d_name, "..") == 0) || (ptrGG->d_type != DT_DIR)) { + continue; + } + + if (strstr(ptrGG->d_name, "GG")) + { + //杀掉GG进程 + killProcess_Root(ptr->d_name); + num++;// 成功杀死一个GG进程 + } + } + closedir(dirGG); + } + } + closedir(dir); + } + return num;// 返回杀死的进程数量 +} + +/// +/// 杀死XS脚本进程 +/// +/// 杀死的进程数量 +int killXscript_Root() { + DIR* dir = NULL; // 目录流指针,用于打开目录 + DIR* dirXS = NULL; // 目录流指针,用于打开目录 + struct dirent* ptr = NULL; // 目录项指针,用于读取目录项 + struct dirent* ptrXS = NULL; // 存储lib文件夹当前目录项 + char filepath[256]; // 存储文件路径的缓冲区 + int num = 0;// 数量 + + // 打开目录 "/data/data" + dir = opendir("/data/data"); + + if (dir != NULL) { + // 循环读取目录下的每一个文件/文件夹 + while ((ptr = readdir(dir)) != NULL) { + //跳过"."和".."目录和文件 + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0) || (ptr->d_type != DT_DIR)) { + continue; + } + + // 生成要读取的文件的路径 + sprintf(filepath, "/data/data/%s/lib", ptr->d_name); + // 打开这个文件夹 + dirXS = opendir(filepath); + if (dirXS != NULL) + { + //读取lib文件夹每一个文件 + while ((ptrXS = readdir(dirXS)) != NULL) + { + //如果动态库名称包含xs脚本则杀死 + if (strstr(ptrXS->d_name, "libxscript")) + { + //杀掉这个XS进程 + killProcess_Root(ptr->d_name); + num++;//成功杀死一个XS进程 + } + } + closedir(dirXS); + } + } + // 关闭目录流 + closedir(dir); + } + return num;//返回杀死的进程数量 +} + + +/// +/// 重启手机 +/// +/// 成功与否 +int rebootsystem_Root() +{ + return system("su -c 'reboot'"); +} +/// +/// 静默安装 指定路径的APK安装包 +/// +/// apk安装包路径 +/// 成功与否 +int installapk_Root(const char* apkPackagePath) +{ + char ml[256]; + sprintf(ml, "pm install %s", apkPackagePath); + return system(ml); +} +/// +/// 静默卸载 指定包名的APK软件 +/// +/// APK包名 +/// 成功与否 +int uninstallapk_Root(const char* packageName) +{ + char ml[256]; + sprintf(ml, "pm uninstall %s", packageName); + return system(ml); +} +/// +/// 执行命令 +/// +/// 命令 +/// 执行状态 +int Cmd(const char* command) { + int status = system(command); + return WEXITSTATUS(status); +} +/// +/// 执行超级命令 +/// +/// 命令 +/// 执行状态 +int Cmd_Root(const char* command) { + // 创建一个完整的命令字符串 + char fullCommand[256]; + snprintf(fullCommand, sizeof(fullCommand), "su -c '%s'", command); + int status = system(fullCommand); + return WEXITSTATUS(status); +} + diff --git a/app/src/main/jni/AlguiMemTool.h.bak b/app/src/main/jni/AlguiMemTool.h.bak new file mode 100644 index 0000000..6909a8f --- /dev/null +++ b/app/src/main/jni/AlguiMemTool.h.bak @@ -0,0 +1,3359 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //kill信号定义在此 + +using namespace std; + +//小白已经在2021年被凌烟kill了 + + + +//AlguiMemTool开源版本:3.0.24109 [🤪警告:仅供Algui外挂模板使用 请勿在其它外挂模板使用可能会发生很多问题] +/* + * MIT License + * + * 版权所有 (c) [2024] ByteCat + * + * 特此授予任何获得本项目及相关文档文件 副本的人,免费使用该软件的权利,包括但不限于使用、复制、修改、合并、出版、分发、再许可和/或出售该软件的副本,以及允许他人这样做,条件如下: + * + * 1. 上述版权声明和本许可声明应包含在所有副本或实质性部分中。 + * 2. 本软件是按“原样”提供的,不附有任何形式的明示或暗示的担保,包括但不限于对适销性、特定用途的适用性和不侵权的担保。 + * 3. 在任何情况下,作者或版权持有人对因使用本项目或与本项目的其他交易而引起的任何索赔、损害或其他责任不承担任何责任,无论是在合同、侵权或其他方面。 + * 4. 请注意,**禁止删除或修改本版权声明和作者信息**,以确保所有用户都能了解软件的来源和许可条款。 + * * **请勿删除下面的信息!** + * 作者:ByteCat *_* + * 游戏逆向交流QQ群:931212209 + * 作者QQ:3353484607 + * 私人定制请联系我 => 接C/C++ Java 安卓开发 联系作者QQ:3353484607 + * 此项目对接到Java请联系我 联系作者QQ:3353484607 + */ + + + + // 更新内容(只列出重要更新): + // 0. 新增完整的联合搜索 完全和GG修改器的联合搜索一样 + // 1. 所有修改内存数据操作 都会对当前进程进行内存保护🛡️ 防止GG模糊搜索 + // 注意:内存保护只对当前进程有效 意味着只有直装能够防模糊 Root修改外部进程时无法防模糊[可能需要附加调试器进行代码注入] + // 所以如果你开发的是Root插件辅助请使用简单粗暴的方式 直接调用killGG_Root();方法来杀掉GG修改器 + // 2. Ca内存已适配android11+ scudo内存分配器 修复了某些Ca内存数据搜不到 + // 3. 完全兼容了模拟器架构 + // 4. 内存搜索已支持范围搜索 例如:10~20 + // 5. 动静态基址修改 已兼容所有基址头 HEAD_XA,HEAD_CD,HEAD_CB + // 6. 所有修改内存数据操作 新增冻结修改 例如:MemoryOffsetWrite("99999", TYPE_DWORD, 0, true); 将bool参数改为true则冻结 否则改为false则停止冻结 + // 7. 新增打印搜索结果列表到指定文件 和 打印冻结列表到指定文件的 调试方法 + // 8. 新增所有常用数据类型和常用内存范围 + // 9. 重写了所有内存筛选规则,对于内存筛选更加精准了 + // 10. 新增一些Root跨进程工具 + // 11. 很多逻辑都进行了原理注释 让新手更好学习 + // + // 2024-10-9 更新内容: + // 0. 联合搜索增加了对范围联合搜索的支持 例:0.1F;3~6D;9 + // 1. 新增内存改善 休眠进程 解冻进程 + // 2. 偏移改善增加了对范围改善和联合改善的支持 + // 2. ~偏移联合改善 -适用于:某些副特征码会变化但是永远只会变为那几个固定值的情况 比如只会变化为22或15或27时可以使用偏移联合改善22;15;27 + // 2. ~偏移范围改善 -适用于:某些副特征码会变化但是只会在一个范围之内变化时 比如特征码始终为1或2或3时 可以使用偏移范围改善使用1~3即可 + // 3. 优化搜索速度 + // 4. 修复潜在溢出 + // 5. 修复一亿个bug + + //初始化ABI字符串 +#if defined(__arm__) && !defined(__aarch64__) //针对 ARM 32 位架构 +#define ABI "ARM32" +#elif defined(__aarch64__) //针对 ARM 64 位架构 +#define ABI "ARM64" +#elif defined(__x86_64__) || defined(_M_X64) //针对 x64 架构 +#define ABI "x64" +#elif defined(__i386__) || defined(_M_IX86) //针对 x86 架构 +#define ABI "x86" +#else // 其他架构或未知架构 +#define ABI "null" +#endif +//内存区域 +#define RANGE_ALL 0 // 所有内存区域 - 全部内存 +#define RANGE_JAVA_HEAP 2 // Java 虚拟机堆内存 - jh内存 +#define RANGE_C_HEAP 1 // C++ 堆内存 - ch内存 +#define RANGE_C_ALLOC 4 // C++ 分配的内存 - ca内存 [已适配 android11+ scudo内存分配器] +#define RANGE_C_DATA 8 // C++ 的数据段 - cd内存 +#define RANGE_C_BSS 16 // C++ 未初始化的数据 - cb内存 +#define RANGE_ANONYMOUS 32 // 匿名内存区域 - a内存 +#define RANGE_JAVA 65536 // Java 虚拟机内存 - j内存 +#define RANGE_STACK 64 // 栈内存区域 - s内存 +#define RANGE_ASHMEM 524288 // Android 共享内存 - as内存 +#define RANGE_VIDEO 1048576 // 视频内存区域 - v内存 +#define RANGE_OTHER -2080896 // 其他内存区域 - o内存 +#define RANGE_B_BAD 131072 // 错误的内存区域 - b内存 +#define RANGE_CODE_APP 16384 // 应用程序代码区域 - xa内存 +#define RANGE_CODE_SYSTEM 32768 // 系统代码区域 - xs内存 + +#if defined(__arm__) || defined(__aarch64__) //arm32和arm64架构 +#define BCMAPSFLAG(mapLine, id) \ + (\ + (id) == RANGE_ALL ? true: \ + (id) == RANGE_JAVA_HEAP ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "dalvik-")!=NULL) : \ + (id) == RANGE_C_HEAP ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[heap]")!=NULL) : \ + (id) == RANGE_C_ALLOC ? (strstr(mapLine, "rw")!=NULL && (strstr(mapLine, "[anon:libc_malloc]")!=NULL || strstr(mapLine,"[anon:scudo")!=NULL)) : \ + (id) == RANGE_C_DATA ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "xp")==NULL && (strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL||strstr(mapLine, "/data/user/")!=NULL)) : \ + (id) == RANGE_C_BSS ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[anon:.bss]")!=NULL) : \ + (id) == RANGE_ANONYMOUS ? (strstr(mapLine, "rw")!=NULL && strchr(mapLine, '[') == NULL && strchr(mapLine, '/') == NULL) : \ + (id) == RANGE_JAVA ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "dalvik-")!=NULL) : \ + (id) == RANGE_STACK ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[stack")!=NULL) : \ + (id) == RANGE_ASHMEM ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "xp")==NULL && strstr(mapLine, "/dev/ashmem/")!=NULL && strstr(mapLine,"dalvik")==NULL) : \ + (id) == RANGE_VIDEO ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "/dev/mali")!=NULL) : \ + (id) == RANGE_B_BAD ? (strstr(mapLine, "r")!=NULL && (strstr(mapLine, "kgsl-3d0")!=NULL||strstr(mapLine, ".ttf")!=NULL)) : \ + (id) == RANGE_CODE_APP ? (strstr(mapLine, " r")!=NULL && strstr(mapLine, "xp")!=NULL && (strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL || (strstr(mapLine, "/dev/ashmem/")!=NULL&& strstr(mapLine,"dalvik")!=NULL) ||strstr(mapLine, "/data/user/")!=NULL)) : \ + (id) == RANGE_CODE_SYSTEM ? (strstr(mapLine, " r")!=NULL && strstr(mapLine, "xp")!=NULL && (strstr(mapLine, "/system")!=NULL || strstr(mapLine, "/vendor") !=NULL || strstr(mapLine, "/apex") !=NULL || strstr(mapLine, "/memfd") !=NULL || strstr(mapLine, "[vdso")!=NULL)) : \ + (id) == RANGE_OTHER ? (strstr(mapLine, "rw")!=NULL && !(strstr(mapLine, "dalvik-")!=NULL||strstr(mapLine, "[heap]")!=NULL||strstr(mapLine, "[anon:libc_malloc]")!=NULL || strstr(mapLine,"[anon:scudo")!=NULL || strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL ||strstr(mapLine, "/data/user/")!=NULL|| strstr(mapLine, "[anon:.bss]")!=NULL || (strchr(mapLine, '[') == NULL && strchr(mapLine, '/') == NULL) ||strstr(mapLine, "[stack")!=NULL||strstr(mapLine, "/dev/ashmem/")!=NULL||strstr(mapLine, "/dev/mali")!=NULL||strstr(mapLine, "kgsl-3d0")!=NULL||strstr(mapLine, ".ttf")!=NULL||strstr(mapLine, "/system")!=NULL||strstr(mapLine, "/vendor")!=NULL||strstr(mapLine, "/apex")!=NULL||strstr(mapLine, "/memfd")!=NULL||strstr(mapLine, "[vdso")!=NULL)) : \ + true\ + ) +#else //x86和x64架构 针对雷电9模拟器《已知bug:cd可能会多搜到一些xa的数据》 +#define BCMAPSFLAG(mapLine, id) \ + (\ + (id) == RANGE_ALL ? true: \ + (id) == RANGE_JAVA_HEAP ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "dalvik-")!=NULL) : \ + (id) == RANGE_C_HEAP ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[heap]")!=NULL) : \ + (id) == RANGE_C_ALLOC ? (strstr(mapLine, "rw")!=NULL && (strstr(mapLine, "[anon:libc_malloc]")!=NULL || strstr(mapLine,"[anon:scudo")!=NULL)) : \ + (id) == RANGE_C_DATA ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "xp")==NULL && (strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL||strstr(mapLine, "/data/user/")!=NULL)) : \ + (id) == RANGE_C_BSS ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[anon:.bss]")!=NULL) : \ + (id) == RANGE_ANONYMOUS ? (strstr(mapLine, "rw")!=NULL && strchr(mapLine, '[') == NULL && strchr(mapLine, '/') == NULL) : \ + (id) == RANGE_JAVA ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "dalvik-")!=NULL) : \ + (id) == RANGE_STACK ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "[stack")!=NULL) : \ + (id) == RANGE_ASHMEM ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "xp")==NULL && strstr(mapLine, "/dev/ashmem/")!=NULL && strstr(mapLine,"dalvik")==NULL) : \ + (id) == RANGE_VIDEO ? (strstr(mapLine, "rw")!=NULL && strstr(mapLine, "/dev/mali")!=NULL) : \ + (id) == RANGE_B_BAD ? (strstr(mapLine, "r")!=NULL && (strstr(mapLine, "kgsl-3d0")!=NULL||strstr(mapLine, ".ttf")!=NULL)) : \ + (id) == RANGE_CODE_APP ? (strstr(mapLine, " r")!=NULL && (strstr(mapLine, "xp")!=NULL||strstr(mapLine, "--p")!=NULL) && (strstr(mapLine, "/data/app/")!=NULL || strstr(mapLine, "/data/data/")!=NULL || (strstr(mapLine, "/dev/ashmem/")!=NULL&& strstr(mapLine,"dalvik")!=NULL) ||strstr(mapLine, "/data/user/")!=NULL)) : \ + (id) == RANGE_CODE_SYSTEM ? (strstr(mapLine, " r")!=NULL && (strstr(mapLine, "xp")!=NULL||strstr(mapLine, "--p")!=NULL) && (strstr(mapLine, "/system")!=NULL || strstr(mapLine, "/vendor") !=NULL || strstr(mapLine, "/apex") !=NULL || strstr(mapLine, "/memfd") !=NULL || strstr(mapLine, "[vdso")!=NULL)) : \ + (id) == RANGE_OTHER ? (strstr(mapLine, "rw") != NULL && !(strstr(mapLine, "dalvik-") != NULL || strstr(mapLine, "[heap]") != NULL || strstr(mapLine, "[anon:libc_malloc]") != NULL || strstr(mapLine, "[anon:scudo") != NULL || strstr(mapLine, "/data/app/") != NULL || strstr(mapLine, "/data/data/") != NULL || strstr(mapLine, "/data/user/") != NULL || strstr(mapLine, "[anon:.bss]") != NULL || (strchr(mapLine, '[') == NULL && strchr(mapLine, '/') == NULL) || strstr(mapLine, "[stack") != NULL || strstr(mapLine, "/dev/ashmem/") != NULL || strstr(mapLine, "/dev/mali") != NULL || strstr(mapLine, "kgsl-3d0") != NULL || strstr(mapLine, ".ttf") != NULL || strstr(mapLine, "/system") != NULL || strstr(mapLine, "/vendor") != NULL || strstr(mapLine, "/apex") != NULL || strstr(mapLine, "/memfd") != NULL || strstr(mapLine, "[vdso") != NULL)) : \ + true\ + ) +#endif +//(id) == RANGE_OTHER ? (strstr(mapLine, "rw") != NULL && strstr(mapLine, "[anon:mmv8]")!=NULL) : \ + +//基址头 +#define HEAD_XA 0 //xa基址头 +#define HEAD_CD 1 //cd基址头 +#define HEAD_CB 2 //cb基址头 [bss] + +//数据类型 +#define TYPE_DWORD 4 // DWORD 类型 - D类型 +#define TYPE_FLOAT 16 // FLOAT 类型 - F类型 +#define TYPE_DOUBLE 64 // DOUBLE 类型 - E类型 +#define TYPE_WORD 2 // WORD 类型 - W类型 +#define TYPE_BYTE 1 // BYTE 类型 - B类型 +#define TYPE_QWORD 32 // QWORD 类型 - Q类型 + +//映射数据类型别名 方便管理 +#define DWORD int32_t // 32 位有符号整数 +#define FLOAT float // 单精度浮点数 +#define DOUBLE double // 双精度浮点数 +#define WORD signed short // 有符号短整型 +#define BYTE signed char // 有符号字符 +#define QWORD int64_t // 64 位有符号整数 + +//范围搜索格式 +#define R_SEPARATE "~" // 范围搜索符号 + +//联合搜索格式 +#define U_DEFRANGE 512 // 默认搜索附近范围 +#define U_SEPARATE ";" // 数据分隔符 +#define U_RANGESEPARATE ":" // 数据范围符【存在两个此符号将视为按顺序搜索】 +#define U_dword "d" // 32 位有符号整数 +#define U_float "f" // 单精度浮点数 +#define U_double "e" // 双精度浮点数 +#define U_word "w" // 有符号短整型 +#define U_byte "b" // 有符号字符 +#define U_qword "q" // 64 位有符号整数 +#define U_DWORD "D" // 32 位有符号整数的大写 +#define U_FLOAT "F" // 单精度浮点数的大写 +#define U_DOUBLE "E" // 双精度浮点数的大写 +#define U_WORD "W" // 有符号短整型的大写 +#define U_BYTE "B" // 有符号字符的大写 +#define U_QWORD "Q" // 64 位有符号整数的大写 + +#define FLAG_FREE "FREE" //修改时只进行冻结的标志 +//结构体声明: +struct Item;//内存数据项 +struct Federated;//联合搜索项 +struct Protection;//内存保护-防模糊优化 +//全局变量 +bool isInit = false;//是否进行了初始化 +bool isSecureWrites = false;//是否进行安全写入 +bool isMapsMemArea = false;//是否为自定义内存区域 +int pid = -1;//存储进程ID +char* packName;//存储进程包名 +int memory = RANGE_ALL;//存储要搜索的内存区域【默认所有内存】 +char* memoryMaps;//存储自定义要搜索的内存区域【maps内存段 使用自定义内存区域可以精准搜索并且提升100倍搜索速度】 +char memPath[1024];//存储进程mem内存映射虚拟文件路径 +char mapsPath[1024];//存储进程maps内存区域映射文件路径 +uint32_t freezeDelay = 200;//冻结修改延迟(毫秒)默认200ms +static bool isFreeze;//是否正在冻结 确保只开一个冻结线程 +vector < Item > FreezeList;//冻结修改项列表 +vector < unsigned long >outcomeList;//最终搜索结果列表 - 存储最终筛选出的数据的内存地址列表 +vector < Protection > ProtectList;//保护项列表 +std::mutex lockMutex;//互斥锁 防止全局数据竞争 + +//函数声明: +//初始化 +int getPID(const char* packageName);// 获取进程ID +int setPackageName(const char* packageName);// 设置目标包名 【注意:这是初始化函数,不调用此函数的话其它内存操作均失效】 +void setIsSecureWrites(bool sw);// 设置安全写入启用状态 + + +//模块[动/静]态基址偏移内存修改 +unsigned long getModuleBaseAddr(const char* module_name, int headType);//获取模块起始地址(基址) +unsigned long jump(unsigned long addr,int count);//跳转指针 +unsigned long jump32(unsigned long addr);//跳转指针 [32位] +unsigned long jump64(unsigned long addr);//跳转指针 [64位] +int setMemoryAddrValue(const char* value, unsigned long addr, int type, bool isFree,bool isSecure);//设置指定内存地址指向的值 🛡️该方法已对当前进程进行保护 防止GG模糊🛡️ +char* getMemoryAddrData(unsigned long addr, int type);//获取指定内存地址的数据 + +//内存搜索 +void setMemoryArea(int memoryArea);//设置要搜索的内存区域 +void setMemoryArea(const char* memoryArea);//设置自定义搜索的内存区域 好处:能精准找到想要的数据,并且搜索速度直接提升100倍 坏处:需要自己去找数据所在的maps内存段 示例:setMemoryArea("/apex/com.android.tethering/lib64/libframework-connectivity-jni.so"); +vector < unsigned long > MemorySearch(const char* value, int type);//内存搜索 【支持范围搜索 格式:最小值~最大值(同GG) 支持联合搜索 格式:值1;值2;值3;n个值:范围 示例:2D;3F;4E:50 或 2D;3F;4E没有范围则使用默认范围,两个范围符::代表按顺序搜索 (同GG)】 +vector < unsigned long > MemorySearchRange(const char* value, int type);//范围内存搜索 【格式:最小值~最大值 (同GG)】 +vector < unsigned long > MemorySearchUnited(const char* value, int type);//联合内存搜索 【格式:值1;值2;值3;n个值:附近范围 示例:2D;3F;4E:50 或 2D;3F;4E没有范围则使用默认范围,两个范围符::代表按顺序搜索 (同GG) 并且值也支持范围例如1~2;3:64】 +vector < unsigned long > ImproveOffset(const char* value, int type, unsigned long offset);//偏移改善 [筛选偏移处特征值 支持联合改善,范围改善] +vector < unsigned long > ImproveOffsetRange(const char* value, int type, unsigned long offset);//偏移范围改善 [筛选偏移处只会在一个范围内变化的特征值] 【格式:最小值~最大值 (同GG)】 +vector < unsigned long > ImproveOffsetUnited(const char* value, int type, unsigned long offset);//偏移联合改善 [筛选偏移处永远只会为某些值的特征值] 【格式:值1;值2;n个值; 示例:2D;3F;4E 或 2D;3~6F;9E 注:联合改善不支持附近范围和顺序改善】 +vector < unsigned long > ImproveValue(const char* value, int type);//改善 [支持联合改善,范围改善] +int MemoryOffsetWrite(const char* value,int type, unsigned long offset, bool isFree,bool isSecure);//结果偏移写入数据 🛡️该方法已对当前进程进行保护 防止GG模糊🛡️ +int getResultCount();//获取最终搜索结果数量 +vector < unsigned long > getResultList();//获取最终搜索结果列表 +int printResultListToFile(const char* filePath);//打印最终搜索结果列表到指定文件 +int clearResultList();//清空最终搜索结果列表 + +//内存保护二次修改 +void MemoryProtect(unsigned long addr); +int getProtectionNum(); +//冻结内存修改 +vector < Item > getFreezeList();//获取冻结修改项列表 +void setFreezeDelayMs(uint32_t delay);//设置冻结修改延迟【毫秒】 +int getFreezeNum();//获取冻结修改项数量 +int addFreezeItem(const char* value, unsigned long addr, int type); // 添加一个冻结修改项 +int removeFreezeItem(unsigned long addr); // 移除一个冻结修改项 +int removeAllFreezeItem();//移除所有冻结修改项 +void* freezeThread(void* arg); // 冻结循环修改线程 +int startAllFreeze(); // 开始冻结所有修改项 +int stopAllFreeze(); // 停止冻结所有修改项 +int printFreezeListToFile(const char* filePath);//打印冻结列表到指定文件 + +//获取内存信息相关工具 +char* getMemoryAddrMapLine(unsigned long address);//获取指定内存地址的Maps映射行 +char* getMapLineMemoryAreaName(const char* mapLine);//获取Maps映射行所在内存区域名称 +char* getMemoryAreaIdName(int memid);//获取指定内存id的内存名称 +char* getMemoryAreaName();//获取当前内存名称 +char* getDataTypeName(int typeId);//获取指定数据类型id的数据类型名称 + +//完全需要ROOT权限的操作 +//PS:告诉一下菜鸟,这些操作涉及到跨进程和系统操作,所以必须完全ROOT,直装也没用 +//--kill-- +int killProcess_Root(const char* packageName); // 杀掉指定包名的进程 (此方法对于执行者自身进程无需Root) +int stopProcess_Root(const char* packageName); // 暂停指定包名的进程 (此方法对于执行者自身进程无需Root) +int resumeProcess_Root(const char* packageName); // 恢复被暂停的指定包名的进程 (此方法对于执行者自身进程无需Root) +void killAllInotify_Root(); // 杀掉所有inotify监视器,防止游戏监视文件变化 +int killGG_Root(); // 杀掉GG修改器 +int killXscript_Root(); // 杀掉XS脚本 +//--Other-- +int rebootsystem_Root(); // 重启手机 +int installapk_Root(const char* apkPackagePath); // 静默安装 指定路径的APK安装包 +int uninstallapk_Root(const char* packageName); // 静默卸载 指定包名的APK软件 +int Cmd(const char* command);//执行命令 +int Cmd_Root(const char* command);//执行超级命令 + +//-内部耗时操作 +//void __MemorySearch__(const char* value, int type);//内存搜索 +//void __MemorySearchRange__(const char* value, int type);//范围内存搜索 +//void __MemorySearchUnited__(const char* value, int type);//联合内存搜索 +//void __ImproveOffset__(const char* value, int type, unsigned long offset);//偏移改善 +//void __ImproveOffsetRange__(const char* value, int type, unsigned long offset);//偏移范围改善 +//void __ImproveOffsetUnited__(const char* value, int type, unsigned long offset);//偏移联合改善 +//void __ImproveValue__(const char* value, int type);//改善 + +/// +/// 内存数据项 +/// +struct Item { + char* value;//值 + unsigned long addr;//地址 + int type; //类型 +}; + +/// +/// 联合搜索项 +/// +struct Federated { + char* value;//搜索值 + int type;//类型 + bool isRange = false;//是否为范围值 例1~20 + char minValue[64 + 2];//最小值(范围值) + char maxValue[64 + 2];//最大值(范围值) + /// + /// 构造 + /// + /// 搜索值 + /// 默认类型:如果值没有+类型字母符则使用此默认类型 + Federated(const char* v, int defType) { + //初始化类型 + if (strstr(v, U_dword) != nullptr || strstr(v, U_DWORD) != nullptr) { + type = TYPE_DWORD; + } + else if (strstr(v, U_float) != nullptr || strstr(v, U_FLOAT) != nullptr) { + type = TYPE_FLOAT; + } + else if (strstr(v, U_double) != nullptr || strstr(v, U_DOUBLE) != nullptr) { + type = TYPE_DOUBLE; + } + else if (strstr(v, U_word) != nullptr || strstr(v, U_WORD) != nullptr) { + type = TYPE_WORD; + } + else if (strstr(v, U_byte) != nullptr || strstr(v, U_BYTE) != nullptr) { + type = TYPE_BYTE; + } + else if (strstr(v, U_qword) != nullptr || strstr(v, U_QWORD) != nullptr) { + type = TYPE_QWORD; + } + else { + type = defType; + } + + //初始化值 + value = strdup(v); + + //去除值中的类型字母符 + int j = 0; //用于跟踪新的字符串索引 + for (int i = 0; value[i] != '\0'; i++) { + //检查当前字符是否为字母 + if (!isalpha(value[i])) { + //如果不是字母,则将其放到前面 + value[j] = value[i]; + j++; + } + } + value[j] = '\0'; //添加字符串结束符 + + //如果是范围值 [这里不要使用strtok来获取 因为如果外部正在使用strtok来初始化时这将影响到外部strtok的分割] + char* start = strstr(value, R_SEPARATE); + if (start != NULL) { + strncpy(minValue, value, start - value); //从开头到分隔符的部分为最小值 + minValue[start - value] = '\0'; //最小值最后的位置添加字符串结束符 + strcpy(maxValue, start + 1); //从分隔符后一个字符开始为最大值 + isRange = true; + } + } + +}; + +/// +/// 内存保护 +/// +struct Protection { + unsigned long addr;//地址 +}; + +///// +///// 内存搜索 +///// +///// 搜索值 +///// 搜索类型 +//void MemorySearch(const char* value, int type) { +// std::thread t([=]() { +// // 加锁,确保在访问 outcomeList 时是安全的 +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __MemorySearch__(value, type); // 假设 __MemorySearch__ 函数会操作 outcomeList +// }); +// t.detach(); +//} +// +///// +///// 内存搜索某个范围区域内的所有值 +///// +///// 范围值 格式:10~20 +///// 搜索类型 +//void MemorySearchRange(const char* value, int type) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __MemorySearchRange__(value, type); +// }); +// t.detach(); +//} +// +///// +///// 联合内存搜索 [注意:附近范围某些情况可能会比GG多4~8个字节] +///// +///// 联合搜索值 格式:值1;值2;值3;n个值:附近范围 +///// 默认联合搜索类型 +//void MemorySearchUnited(const char* value, int type) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __MemorySearchUnited__(value, type); +// }); +// t.detach(); +//} +// +///// +///// 从当前搜索结果中 筛选结果附近指定偏移处具有指定特征值的结果 +///// +///// 数据附近特征值 +///// 特征值数据类型 +///// 特征值相对主数据的偏移量 +//void ImproveOffset(const char* value, int type, unsigned long offset) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __ImproveOffset__(value, type, offset); +// }); +// t.detach(); +//} +// +///// +///// 从当前搜索结果中 筛选指定偏移处的值在这个范围内的结果 +///// +///// 范围值[格式:最小~最大] +///// 数据类型 +//void ImproveOffsetRange(const char* value, int type, unsigned long offset) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __ImproveOffsetRange__(value, type, offset); +// }); +// t.detach(); +//} +// +///// +///// 从当前搜索结果中 筛选指定偏移处的值为联合值中的某一个值的结果 +///// +///// 联合筛选值 +///// 默认类型 +//void ImproveOffsetUnited(const char* value, int type, unsigned long offset) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __ImproveOffsetUnited__(value, type, offset); +// }); +// t.detach(); +//} +// +///// +///// 从当前搜索结果中 直接改善 [支持范围改善和联合改善] +///// +///// 改善值 +///// 默认类型 +//void ImproveValue(const char* value, int type) { +// std::thread t([=]() { +// std::lock_guard lock(lockMutex); //锁定互斥量 +// __ImproveValue__(value, type); +// }); +// t.detach(); +//} + +/// +/// 通过包名获取进程ID +/// +/// 进程APK包名 +/// 进程ID +int getPID(const char* packageName) +{ + int id = -1; // 进程ID,初始化为-1,表示未找到 + DIR* dir; // 目录流指针 + FILE* fp; // 文件指针 + char filename[64]; // 存储/proc/[pid]/cmdline路径 + char cmdline[64]; // 存储进程的命令行信息 + struct dirent* entry; // 目录项结构体,用于存储目录中的条目 + + dir = opendir("/proc"); // 打开/proc目录 + if (dir != NULL) { + while ((entry = readdir(dir)) != NULL) // 遍历/proc目录下的每一个条目 + { + id = atoi(entry->d_name); // 将条目名转换为进程ID + if (id >= 0) // 过滤非进程ID的条目 + { + sprintf(filename, "/proc/%d/cmdline", id); // 生成进程命令行文件路径 + fp = fopen(filename, "r"); // 打开命令行文件 + if (fp != NULL) + { + fgets(cmdline, sizeof(cmdline), fp); // 读取命令行信息 + fclose(fp); // 关闭文件 + if (strcmp(packageName, cmdline) == 0) // 比较包名与命令行信息 + { + closedir(dir); // 关闭目录 + return id;//找到了 + } + } + } + } + closedir(dir); // 关闭目录 + } + return -1; // 未找到进程,返回-1 +} + +/// +/// 设置包名,函数内部将获取该包名的进程ID方便之后操作 +/// +/// 进程APK包名 +/// 进程ID +int setPackageName(const char* packageName) +{ + pid = getPID(packageName); + if (pid != -1) { + sprintf(memPath, "/proc/%d/mem", pid);//初始化构造mem内存文件路径 + sprintf(mapsPath, "/proc/%d/maps", pid);//初始化构造maps内存文件路径 + isInit = true;//进行了初始化 + packName = strdup(packageName);//设置包名 + //outcomeList.reserve(100000000); // 预分配足够的内存 + } + return pid; +} + +/// +/// 设置安全写入的启用状态 +/// +/// 状态 +void setIsSecureWrites(bool sw) { + isSecureWrites = sw; +} + + + + + + +/// +/// 获取动态共享库的基址(起始地址) +/// +/// 动态共享库名称(后缀.so文件) +/// 基址头类型 +/// 基地址 +unsigned long getModuleBaseAddr(const char* module_name, int headType) +{ + if (!isInit) { + //未进行初始化 + return 0; + } + + //存储模块名称 + char* mod_name = strdup(module_name); //复制字符串 + if (mod_name == NULL) { + perror("strdup failed"); + return 0; + } + //检测如果包含:bss则去除 + char* pos = strstr(mod_name, ":bss"); + if (pos != NULL) { + //如果找到bss + *pos = '\0'; //将:bss换成字符串中断符进行截断 + } + FILE* fp; //文件指针 + unsigned long start = 0;//存储获取到的模块的起始地址 + unsigned long end = 0;//存储获取到的模块的结束地址 + char line[1024]; //存储读取的行 + bool cb = false; //是否开始查询bss + bool isFoundIt = false;//是否找到 + fp = fopen(mapsPath, "r"); + if (fp != NULL) + { + //逐行读取文件 + while (fgets(line, sizeof(line), fp)) + { + if (isMapsMemArea) { + //对于自定义内存区域 + if (strstr(line, memoryMaps)) { + //提取起始地址和结束地址 + sscanf(line, "%lx-%lx", &start, &end); + break; + } + } + else { + switch (headType) { + case HEAD_XA: + { + //查找行中是否包含模块名 + if (strstr(line, mod_name) && BCMAPSFLAG(line, RANGE_CODE_APP)) + { + //提取起始地址和结束地址 + sscanf(line, "%lx-%lx", &start, &end); + + //转换特殊地址 + if (start == 0x8000) { + start = 0; + } + isFoundIt = true;//找到了 + } + } + break; + case HEAD_CD://由于cd的结束地址是cb的起始地址 所以要先找到cb的起始地址 因此这里使用贯穿 + case HEAD_CB: + { + //找到模块名之后才开始查询bss + if (strstr(line, mod_name) && BCMAPSFLAG(line, RANGE_CODE_APP)) + { + cb = true; + } + if (cb) + { + if (BCMAPSFLAG(line, RANGE_C_BSS)) + { + //提取起始地址和结束地址 + sscanf(line, "%lx-%lx", &start, &end); + //如果是cb则直接找到 + if (headType == HEAD_CB) { + isFoundIt = true;//找到了 + break; + } + //如果是cd则开始查cd + if (headType == HEAD_CD) { + //将cb起始地址格式化为结束地址作为cd的筛选条件 + char str[100]; + sprintf(str, "-%lx", start); + + //重置文件指针到文件的开始位置 + fseek(fp, 0, SEEK_SET); + //重新逐行读取文件 + while (fgets(line, sizeof(line), fp)) { + if (strstr(line, str)) + { + //提取起始地址和结束地址 + sscanf(line, "%lx-%lx", &start, &end); + isFoundIt = true;//找到了 + break; + } + } + //重置文件指针到文件的开始位置 + fseek(fp, 0, SEEK_SET); + } + } + } + } + break; + } + //检查是否找到 + if (isFoundIt) { + break;//跳出循环 + } + } + + } + //关闭文件 + fclose(fp); + } + //释放模块字符串 + free(mod_name); + // 返回模块的基地址 + return start; +} +/// +/// 跳转到指定内存地址的指针 +/// +/// 内存地址 +// 要读取的字节数 +/// 指针地址 +unsigned long jump(unsigned long addr,int count) +{ + int fd = open(memPath, O_RDONLY); + if (fd >= 0) { + unsigned long pAddr=0; + ssize_t r = pread64(fd, &pAddr, count, addr); + if(r<0){ + pAddr = 0; + } + close(fd); + return pAddr; + } + return 0; +} +/// +/// 跳转到指定内存地址的指针【32位】 +/// +/// 内存地址 +/// 指针地址 +unsigned long jump32(unsigned long addr) +{ + return jump(addr,4);//读取4字节 +} +/// +/// 跳转到指定内存地址的指针【64位】 +/// +/// 内存地址 +/// 指针地址 +unsigned long jump64(unsigned long addr) +{ + return jump(addr,8);//读取8字节 +} + + +/// +/// 设置指定内存地址指向的值 +/// +/// 设置的值 +/// 内存地址 +/// 数据类型 +/// 是否冻结 +/// 设置成功与否 +int setMemoryAddrValue(const char* value, unsigned long addr, int type, bool isFree,bool isSecure) +{ +int pageSize = getpagesize(); +void* addrToProtect; +unsigned long alignedAddr; + if (!isInit) { + //未进行初始化 + return -1; + } + + if(isSecure){ + addrToProtect = (void*)(addr); + + alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1);} + //是否冻结修改 + if (isFree) { + addFreezeItem(value, addr, type);//添加一个冻结修改项目 + startAllFreeze();//开始冻结 + return 0; + } + else { + + int fd = open(memPath, O_RDWR | O_SYNC); + //打开maps文件 + FILE* maps = fopen(mapsPath, "r"); + if (fd >= 0 && maps) { + switch (type) { + case TYPE_DWORD: + { + + DWORD v = atoi(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(DWORD), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(FLOAT), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(value, NULL); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(DOUBLE), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(QWORD), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(WORD), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(value); + ; + int res = mprotect((void*)alignedAddr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC); + + pwrite64(fd, &v, sizeof(BYTE), addr); + res = mprotect((void*)alignedAddr, pageSize, PROT_EXEC); + + } + break; + } + + + } + if (fd >= 0) { + close(fd); + } + + if (maps) { + fclose(maps); + } + removeFreezeItem(addr);//移除这个冻结修改项目(如果存在) + return 0; + } + + + return -1; +} + +/// +/// 获取指定内存地址的数据 +/// +/// 内存地址 +/// 数据类型 +/// 获取到的数据[指针记得用完调用free释放] +char* getMemoryAddrData(unsigned long addr, int type) +{ + if (!isInit) { + //未进行初始化 + return "NULL"; + } + + int fd = open(memPath, O_RDONLY); + if (fd >= 0) { + int size = -1; + void* buff; + char* value = "NULL"; + + switch (type) + { + case TYPE_DWORD: + { + size = sizeof(DWORD);//存储要读取的字节数 + buff = (void*)malloc(size);//分配一块内存来存储读取到的数据 + pread64(fd, buff, size, addr);//从mem文件指定内存地址读取数据到buff + DWORD v = *(DWORD*)buff;//解析获取到的数据 + int len = snprintf(NULL, 0, "%d", v);//获取数据的字符长度 + value = (char*)malloc(len + 1);//字符串动态分配足够内存来存储数据 确保能足够存储数据的字符数量 + sprintf(value, "%d", v);//将数据格式化为字符串 + } + break; + case TYPE_FLOAT: + { + size = sizeof(FLOAT); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + FLOAT v = *(FLOAT*)buff; + int len = snprintf(NULL, 0, "%f", v); + value = (char*)malloc(len + 1); + sprintf(value, "%f", v); + //检测是否需要使用科学记数法来格式化 + bool isScience = true; + for (int i = 0; i < len; i++) { + if (value[i] == '.' || value[i] == '-') { + continue; + } + if (value[i] != '0') { + isScience = false; + } + } + if (isScience) { + sprintf(value, "%.8e", v); + } + if (strstr(value, "nan")) { + value = "NaN"; + } + } + break; + case TYPE_DOUBLE: + { + size = sizeof(DOUBLE); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + DOUBLE v = *(DOUBLE*)buff; + int len = snprintf(NULL, 0, "%f", v); + value = (char*)malloc(len + 1); + sprintf(value, "%f", v); + //检测是否需要使用科学记数法来格式化 + bool isScience = true; + if (len < 20) { + for (int i = 0; i < len; i++) { + if (value[i] == '.' || value[i] == '-') { + continue; + } + if (value[i] != '0') { + isScience = false; + } + } + } + if (isScience) { + sprintf(value, "%.8e", v); + } + if (strstr(value, "nan")) { + value = "NaN"; + } + } + break; + case TYPE_QWORD: + { + size = sizeof(QWORD); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + QWORD v = *(QWORD*)buff; + int len = snprintf(NULL, 0, "%lld", v); + value = (char*)malloc(len + 1); + sprintf(value, "%lld", v); + } + break; + case TYPE_WORD: + { + size = sizeof(WORD); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + WORD v = *(WORD*)buff; + int len = snprintf(NULL, 0, "%d", v); + value = (char*)malloc(len + 1); + sprintf(value, "%d", v); + } + break; + case TYPE_BYTE: + { + size = sizeof(BYTE); + buff = (void*)malloc(size); + pread64(fd, buff, size, addr); + BYTE v = *(BYTE*)buff; + int len = snprintf(NULL, 0, "%d", v); + value = (char*)malloc(len + 1); + sprintf(value, "%d", v); + } + break; + } + + close(fd); + if (buff != NULL) { + free(buff); + } + return value; + } + return "NULL"; +} + + +/// +/// 设置要搜索的内存区域,初始化内存区域方便之后内存搜索 +/// +/// 内存区域 +void setMemoryArea(int memoryArea) +{ + memory = memoryArea; + isMapsMemArea = false; +} +/// +/// 设置自定义内存区域 好处:能精准找到想要的数据,并且搜索速度直接提升100倍 坏处:需要自己去找数据所在的maps内存段 示例:setMemoryArea("/apex/com.android.tethering/lib64/libframework-connectivity-jni.so"); +/// +/// maps内存段 +void setMemoryArea(const char* memoryArea) +{ + memoryMaps = strdup(memoryArea); + isMapsMemArea = true; +} +/// +/// 内存搜索 +/// +/// 搜索值 +/// 搜索类型 +/// 搜索结果列表 +vector < unsigned long > MemorySearch(const char* value, int type) +{ +if(getFreezeNum()>0){ +for(int i=0;i0){ + for(int i=0;i= 0 && maps) + { + + //清空搜索结果列表 + //clearResultList(); + + char mapLine[1024]; //用于存储每行读取到的信息 + unsigned long start; //存储内存起始地址 + unsigned long end; //存储内存结束地址 + //逐行读取maps文件每行信息 + while (fgets(mapLine, sizeof(mapLine), maps)) + { + //如果当前行匹配内存标志则进行搜索 + if (BCMAPSFLAG(mapLine, memory)) + { + //从该行中解析出内存区域的起始和结束地址 + sscanf(mapLine, "%lx-%lx", &start, &end); + int size = end - start; //计算内存区域的大小 + void* buf = (void*)malloc(size);//存储指向起始地址的指针 + int ret = pread64(mem, buf, size, start);//buf指向起始地址 + switch (type) + { + case TYPE_DWORD: + { + DWORD v = atoi(value);//存储要搜索的数值 + int increment = sizeof(DWORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(DWORD*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(value); + int increment = sizeof(FLOAT);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(FLOAT*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(value, NULL); + //DOUBLE v = atof(value); + int increment = sizeof(DOUBLE);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(DOUBLE*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(value); + int increment = sizeof(QWORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(QWORD*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(value); + int increment = sizeof(WORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(WORD*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(value); + int increment = sizeof(BYTE);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + //如果当前buf+偏移中的数据等于要查找的数据则将该地址加入搜索结果列表中 + if (*(BYTE*)((char*)buf + index) == v) + { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + } + if (buf != NULL) { + free(buf); + } + } + } + } + if (mem >= 0) { + close(mem); + } + + if (maps) { + fclose(maps); + } + } + return outcomeList; +} + +/// +/// 内存搜索某个范围区域内的所有值 +/// +/// 范围值 格式:10~20 +/// 搜索类型 +/// 搜索结果列表 +vector < unsigned long > MemorySearchRange(const char* value, int type) +{ +if(getFreezeNum()>0){ +for(int i=0;i0){ + for(int i=0;i= 0 && maps) + { + //清空搜索结果列表 + //clearResultList(); + //outcomeList.reserve(100000000); // 预分配足够的内存 + char mapLine[1024]; //用于存储每行读取到的信息 + unsigned long start; //存储内存起始地址 + unsigned long end; //存储内存结束地址 + char formatString[50]; //存储格式规则 + + //逐行读取maps每一行 + while (fgets(mapLine, sizeof(mapLine), maps)) + { + + //如果当前行匹配内存标志则进行搜索 + if (BCMAPSFLAG(mapLine, memory)) + { + //从该行中解析出内存区域的起始和结束地址 + sscanf(mapLine, "%lx-%lx", &start, &end); + int size = end - start; //计算内存区域的大小 + void* buf = (void*)malloc(size);//存储指向起始地址的指针 + int ret = pread64(mem, buf, size, start);//buf指向起始地址 + switch (type) + { + case TYPE_DWORD: + { + DWORD minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%d", R_SEPARATE, "%d"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(DWORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + DWORD v = *(DWORD*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index);//添加几千万以上大量数据时可能会影响性能 + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_FLOAT: + { + FLOAT minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%f", R_SEPARATE, "%f"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(FLOAT);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + FLOAT v = *(FLOAT*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_DOUBLE: + { + DOUBLE minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%f", R_SEPARATE, "%f"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(DOUBLE);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + DOUBLE v = *(DOUBLE*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_QWORD: + { + QWORD minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%lld", R_SEPARATE, "%lld"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(QWORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + QWORD v = *(QWORD*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_WORD: + { + WORD minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%d", R_SEPARATE, "%d"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(WORD);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + WORD v = *(WORD*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + case TYPE_BYTE: + { + BYTE minv, maxv;//存储最小值和最大值 + sprintf(formatString, "%s%s%s", "%d", R_SEPARATE, "%d"); + sscanf(value, formatString, &minv, &maxv);//解析范围值 + int increment = sizeof(BYTE);//偏移增量 + if (ret == size) + { + int index = 0;//存储偏移 + while (index < size) + { + BYTE v = *(BYTE*)((char*)buf + index); + //如果这个数据大于等于最小值并且小于等于最大值的话就加入最终搜索结果列表 + if (v >= minv && v <= maxv) { + outcomeList.push_back(start + index); + } + index += increment;//偏移移动到下一个位置 + } + } + } + break; + } + if (buf != NULL) { + free(buf); + } + + } + } + } + if (mem >= 0) { + close(mem); + } + + if (maps) { + fclose(maps); + } + } + return outcomeList; +} + + + +/// +/// 联合内存搜索 [注意:附近范围某些情况可能会比GG多4~8个字节 比如对于1~2;5:50这种情况gg的联合范围搜索只能按顺序 而这里是不按顺序的 对于联合范围加上::按顺序搜索就和GG联合范围一致了] +/// +/// 联合搜索值 格式:值1;值2;值3;n个值:附近范围 (没有范围则使用默认范围 两个范围符::代表按顺序搜索) 示例:7F;2D;3E:30 或 7F;2D;3E(未设置范围则使用默认范围) 并且值也支持范围例如1~2;3:64 +/// 默认联合搜索类型:对于未加类型符的值将使用此类型 例如1D;2;3E中的2将使用此类型 +/// 搜索结果 +vector < unsigned long > MemorySearchUnited(const char* value, int type) { +if(getFreezeNum()>0){ +for(int i=0;i0){ + for(int i=0;i valueList; //存储分割出的所有数值的列表 + //获取第一个分割部分 + const char* token = strtok(valueCopy, U_SEPARATE); + //逐个获取剩余的分割部分 + while (token != NULL) { + valueList.emplace_back(token, type); //保存分割出的值 + token = strtok(NULL, U_SEPARATE); // 获取下一个分割部分 + } + + //开始联合搜索 + if (!valueList.empty()) { + ///先搜第一个值的内存地址 作为起始地址 [如果第一个值是范围值内部将自动进行范围搜索这里无需判断] + MemorySearch(valueList[0].value, valueList[0].type); + //搜索剩余值 + //打开mem内存文件 + int mem = open(memPath, O_RDONLY); + if (mem >= 0) { + vector < unsigned long >offsetFilterResults; + for (int i = 0; i < outcomeList.size(); i++) + { + vector < Item > results;//存储当前起始地址附近找到的值列表 + //开始查找当前起始地址附近的值 + for (int j = 0; j < valueList.size(); j++) + { + switch (valueList[j].type) + { + case TYPE_DWORD: + { + DWORD v; + DWORD minv; + DWORD maxv; + if (valueList[j].isRange) { + minv = atoi(valueList[j].minValue); + maxv = atoi(valueList[j].maxValue); + } + else { + v = atoi(valueList[j].value); + } + int size = sizeof(DWORD); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + DWORD eV = *(DWORD*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + + } + offset += size; + } + free(buf); + } + break; + case TYPE_FLOAT: + { + FLOAT v; + FLOAT minv; + FLOAT maxv; + if (valueList[j].isRange) { + minv = atof(valueList[j].minValue); + maxv = atof(valueList[j].maxValue); + } + else { + v = atof(valueList[j].value); + } + int size = sizeof(FLOAT); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + FLOAT eV = *(FLOAT*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + case TYPE_DOUBLE: + { + DOUBLE v; + DOUBLE minv; + DOUBLE maxv; + if (valueList[j].isRange) { + minv = strtod(valueList[j].minValue, NULL); + maxv = strtod(valueList[j].maxValue, NULL); + } + else { + v = strtod(valueList[j].value, NULL); + } + int size = sizeof(DOUBLE); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + DOUBLE eV = *(DOUBLE*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + case TYPE_QWORD: + { + QWORD v; + QWORD minv; + QWORD maxv; + if (valueList[j].isRange) { + minv = atoll(valueList[j].minValue); + maxv = atoll(valueList[j].maxValue); + } + else { + v = atoll(valueList[j].value); + } + int size = sizeof(QWORD); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + QWORD eV = *(QWORD*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + case TYPE_WORD: + { + WORD v; + WORD minv; + WORD maxv; + if (valueList[j].isRange) { + minv = (WORD)atoi(valueList[j].minValue); + maxv = (WORD)atoi(valueList[j].maxValue); + } + else { + v = (WORD)atoi(valueList[j].value); + } + int size = sizeof(WORD); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + WORD eV = *(WORD*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + case TYPE_BYTE: + { + BYTE v; + BYTE minv; + BYTE maxv; + if (valueList[j].isRange) { + minv = (BYTE)atoi(valueList[j].minValue); + maxv = (BYTE)atoi(valueList[j].maxValue); + } + else { + v = (BYTE)atoi(valueList[j].value); + } + int size = sizeof(BYTE); + void* buf = (void*)malloc(size); + int range = unitedRange; + //范围根据数据类型自动对齐 + if (range % size != 0) { + range = range + (size - (range % size)); + } + int offset = 0; + if (!isOrder) { + offset = -range; + } + + while (offset < range) + { + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + if (ret == size) + { + BYTE eV = *(BYTE*)buf; + if (valueList[j].isRange) { + //对于范围 + if (eV >= minv && eV <= maxv) + { + //goto add; + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + else { + //对于单值 + if (eV == v) + { + //add: + Item table; + table.value = strdup(valueList[j].value); + table.addr = outcomeList[i] + offset; + table.type = valueList[j].type; + results.push_back(table); + //break; + } + } + } + offset += size; + } + free(buf); + } + break; + } + } + + if (results.size() >= valueList.size()) { + //检查当前找到的附近值向量中是否包含搜索值向量中的所有元素 (包含所有才添加到结果) + bool isAdd = true; + for (int i = 0; i < valueList.size(); i++) + { + bool found = false; + for (int j = 0; j < results.size(); j++) + { + if (strcmp(results[j].value, valueList[i].value) == 0) { + found = true; + break; + } + } + if (!found) { + isAdd = false; + break; + } + } + + if (isAdd) { + for (int h = 0; h < results.size(); h++) + { + //防止重复添加 + if (find(offsetFilterResults.begin(), offsetFilterResults.end(), results[h].addr) == offsetFilterResults.end()) { + //if (labs(outcomeList[i] - results[h]) <= unitedRange) { + offsetFilterResults.push_back(results[h].addr); + //} + } + } + } + } + } + + close(mem); + //筛选完成则清空最终筛选结果列表 + outcomeList.clear(); + //将新筛选出的结果列表添加进最终筛选结果列表 + for (int i = 0; i < offsetFilterResults.size(); i++) + { + outcomeList.push_back(offsetFilterResults[i]); + } + //升序排序结果 + sort(outcomeList.begin(), outcomeList.end()); + } + } + free(valueCopy); //释放副本内存 + } + return outcomeList; +} + + + +/// +/// 从当前搜索结果中 筛选结果附近指定偏移处具有指定特征值的结果 [支持范围改善,联合改善] +/// +/// 数据附近特征值 +/// 特征值数据类型 +/// 特征值相对主数据的偏移量 +/// 最终筛选结果列表 +vector < unsigned long > ImproveOffset(const char* value, int type, unsigned long offset) +{ + if (isInit) { + //如果包含分隔符则使用偏移联合改善 + if (strstr(value, U_SEPARATE)) { + return ImproveOffsetUnited(value, type, offset); + } + //如果包含范围则使用偏移范围改善 + if (strstr(value, R_SEPARATE) && !strstr(value, U_SEPARATE)) { + return ImproveOffsetRange(value, type, offset); + } + vector < unsigned long >offsetFilterResults;//临时筛选结果列表 - 临时存储当前偏移筛选出的附近拥有特征值的数据 + int fd = open(memPath, O_RDONLY); + if (fd >= 0) + { + switch (type) + { + case TYPE_DWORD: + { + DWORD v = atoi(value); + int size = sizeof(DWORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(DWORD*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(value); + int size = sizeof(FLOAT); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(FLOAT*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(value, NULL); + int size = sizeof(DOUBLE); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(DOUBLE*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(value); + int size = sizeof(QWORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(QWORD*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(value); + int size = sizeof(WORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(WORD*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(value); + int size = sizeof(BYTE); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + if (*(BYTE*)buf == v) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + } + close(fd); + //筛选完成则清空最终筛选结果列表 + outcomeList.clear(); + //将新筛选出的结果列表添加进最终筛选结果列表 + for (int i = 0; i < offsetFilterResults.size(); i++) + { + outcomeList.push_back(offsetFilterResults[i]); + } + } + } + return outcomeList; +} + +/// +/// 从当前搜索结果中 筛选指定偏移处的值在这个范围内的结果 [偏移范围改善] 适用于:某些特征码会变化但是只会在一个范围之内变化时 比如特征码始终为1或2或3时 可以使用偏移范围改善使用1~3即可 +/// +/// 范围值[格式:最小~最大 例如1~20] +/// 数据类型 +/// +vector < unsigned long > ImproveOffsetRange(const char* value, int type, unsigned long offset) { + if (isInit) { + char minValue[64 + 2]; + char maxValue[64 + 2]; + const char* start = strstr(value, R_SEPARATE); + if (start != NULL) { + strncpy(minValue, value, start - value); //从开头到分隔符的部分为最小值 + minValue[start - value] = '\0'; //最小值最后的位置添加字符串结束符 + strcpy(maxValue, start + 1); //从分隔符后一个字符开始为最大值 + } + vector < unsigned long >offsetFilterResults;//临时筛选结果列表 - 临时存储当前偏移筛选出的附近拥有特征值的数据 + int fd = open(memPath, O_RDONLY); + if (fd >= 0) + { + switch (type) + { + case TYPE_DWORD: + { + DWORD minv = atoi(minValue); + DWORD maxv = atoi(maxValue); + int size = sizeof(DWORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + DWORD bV = *(DWORD*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_FLOAT: + { + FLOAT minv = atof(minValue); + FLOAT maxv = atof(maxValue); + int size = sizeof(FLOAT); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + FLOAT bV = *(FLOAT*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_DOUBLE: + { + DOUBLE minv = strtod(minValue, NULL); + DOUBLE maxv = strtod(maxValue, NULL); + int size = sizeof(DOUBLE); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + DOUBLE bV = *(DOUBLE*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_QWORD: + { + QWORD minv = atoll(minValue); + QWORD maxv = atoll(maxValue); + int size = sizeof(QWORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + QWORD bV = *(QWORD*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_WORD: + { + WORD minv = (WORD)atoi(minValue); + WORD maxv = (WORD)atoi(maxValue); + int size = sizeof(WORD); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + WORD bV = *(WORD*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + case TYPE_BYTE: + { + BYTE minv = (BYTE)atoi(minValue); + BYTE maxv = (BYTE)atoi(maxValue); + int size = sizeof(BYTE); + void* buf = (void*)malloc(size); + //遍历搜索到的数据的内存地址列表 + for (int i = 0; i < outcomeList.size(); i++) + { + //检查这个从内存地址偏移[offset]之后的内存地址指向的值是否为v + int ret = pread64(fd, buf, size, outcomeList[i] + offset); + if (ret == size) + { + BYTE bV = *(BYTE*)buf; + if (bV >= minv && bV <= maxv) + { + //如果匹配成功则将这个内存地址添加进偏移筛选结果列表 + offsetFilterResults.push_back(outcomeList[i]); + } + } + } + free(buf); + } + break; + } + close(fd); + //筛选完成则清空最终筛选结果列表 + outcomeList.clear(); + //将新筛选出的结果列表添加进最终筛选结果列表 + for (int i = 0; i < offsetFilterResults.size(); i++) + { + outcomeList.push_back(offsetFilterResults[i]); + } + } + } + return outcomeList; + +} + +/// +/// 从当前搜索结果中 筛选指定偏移处的值为联合值中的某一个值的结果 [偏移联合改善] 适用于:某些特征码会变化但是永远只会变为那几个固定值的情况 比如只会变化为22或15或27时可以使用偏移联合改善22;15;27 +/// +/// 联合筛选值:[格式:值1;值2;值3;n个值 示例:7F;2D;3E 并且值也支持范围例如1~2;3 注:改善不支持顺序改善和区间范围] +/// 默认类型:对于未将类型符的值使用此类型 例如1D;2;3E中的2将使用此类型 +/// +vector < unsigned long > ImproveOffsetUnited(const char* value, int type, unsigned long offset) { + if (isInit) { + //LOGD("联合改善调试", "start"); + char* valueCopy = strdup(value);//创建副本内存因为之后要进行修改传入的字符串 + + //获取联合改善数值到列表 + vector < Federated > valueList; //存储分割出的所有数值的列表 + //获取第一个分割部分 + const char* token = strtok(valueCopy, U_SEPARATE); + //逐个获取剩余的分割部分 + while (token != NULL) { + valueList.emplace_back(token, type); //保存分割出的值 + token = strtok(NULL, U_SEPARATE); // 获取下一个分割部分 + } + + //开始联合改善 + if (!valueList.empty()) { + //打开mem内存文件 + int mem = open(memPath, O_RDONLY); + if (mem >= 0) { + vector < unsigned long >filterResults;//存储临时改善结果列表 + for (int i = 0; i < outcomeList.size(); i++) + { + for (int j = 0; j < valueList.size(); j++) + { + bool isF = false;//标记是否已找到 + switch (valueList[j].type) + { + case TYPE_DWORD: + { + int size = sizeof(DWORD); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + DWORD eV = *(DWORD*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + DWORD minv = atoi(valueList[j].minValue); + DWORD maxv = atoi(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + DWORD v = atoi(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_FLOAT: + { + int size = sizeof(FLOAT); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + FLOAT eV = *(FLOAT*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + FLOAT minv = atof(valueList[j].minValue); + FLOAT maxv = atof(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + FLOAT v = atof(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_DOUBLE: + { + int size = sizeof(DOUBLE); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + DOUBLE eV = *(DOUBLE*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + DOUBLE minv = strtod(valueList[j].minValue, NULL); + DOUBLE maxv = strtod(valueList[j].maxValue, NULL); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + DOUBLE v = strtod(valueList[j].value, NULL); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_QWORD: + { + int size = sizeof(QWORD); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + QWORD eV = *(QWORD*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + QWORD minv = atoll(valueList[j].minValue); + QWORD maxv = atoll(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + QWORD v = atoll(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_WORD: + { + int size = sizeof(WORD); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + WORD eV = *(WORD*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + WORD minv = (WORD)atoi(valueList[j].minValue); + WORD maxv = (WORD)atoi(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + WORD v = (WORD)atoi(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + case TYPE_BYTE: + { + int size = sizeof(BYTE); + void* buf = (void*)malloc(size); + int ret = pread64(mem, buf, size, outcomeList[i] + offset); + BYTE eV = *(BYTE*)buf; + if (ret == size) + { + if (valueList[j].isRange) { + BYTE minv = (BYTE)atoi(valueList[j].minValue); + BYTE maxv = (BYTE)atoi(valueList[j].maxValue); + if (eV >= minv && eV <= maxv) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + else { + BYTE v = (BYTE)atoi(valueList[j].value); + if (eV == v) { + filterResults.push_back(outcomeList[i]); + isF = true; + } + } + } + free(buf); + } + break; + } + //找到则结束循环 开始匹配下一轮的值 + if (isF) { + break; + } + } + } + + close(mem); + //筛选完成则清空最终筛选结果列表 + outcomeList.clear(); + //将新筛选出的结果列表添加进最终筛选结果列表 + for (int i = 0; i < filterResults.size(); i++) + { + outcomeList.push_back(filterResults[i]); + } + //升序排序结果 + //sort(outcomeList.begin(), outcomeList.end()); + } + } + free(valueCopy); //释放副本内存 + } + return outcomeList; +} +/// +/// 从当前搜索结果中 直接改善 [支持范围改善和联合改善] +/// +/// 改善值 +/// 默认类型 +/// 结果 +vector < unsigned long > ImproveValue(const char* value, int type) { + return ImproveOffset(value, type, 0); +} +/// +/// 从最终所有筛选结果的指定偏移处进行写入数据 +/// +/// 写入的数据 +/// 写入数据类型 +/// 相对筛选结果处的偏移量 +/// 是否冻结写入 +/// 写入成功与否 +int MemoryOffsetWrite(const char* value, int type, unsigned long offset, bool isFree,bool isSecure) +{ + if (!isInit) { + //没有进行初始化 + return -1; + } + isSecureWrites=isSecure; + int pageSize = getpagesize(); + int fd = open(memPath, O_RDWR | O_SYNC); + //打开maps文件 + FILE* maps = fopen(mapsPath, "r"); + if (fd >= 0 && maps) + { + + for (int i = 0; i < outcomeList.size(); i++) { + if(isSecureWrites){ + MemoryProtect(outcomeList[i] + offset);} + if (isFree) { + + addFreezeItem(value, outcomeList[i] + offset, type); + startAllFreeze(); + } + else { + + switch (type) + { + case TYPE_DWORD: + { + DWORD v = atoi(value); + + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(DWORD), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(value); + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(FLOAT), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(value, NULL); + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(DOUBLE), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(value); + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(DOUBLE), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(value); + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(WORD), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(value); + + void* addrToProtect = (void*)(outcomeList[i] + offset); + unsigned long alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); + pwrite64(fd, &v, sizeof(BYTE), outcomeList[i] + offset); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + } + + removeFreezeItem(outcomeList[i] + offset);//关闭冻结 + } + } + return 0; + } + if (fd >= 0) { + close(fd); + } + + if (maps) { + fclose(maps); + } + return -1;//内存写入成功 +} + +/// +/// 获取最终搜索结果数量 +/// +/// 最终搜索结果数量 +int getResultCount() +{ + return outcomeList.size(); +} + +/// +/// 获取最终搜索结果列表 +/// +/// 最终搜索结果列表 +vector < unsigned long > getResultList() +{ + return outcomeList; +} + +/// +/// 打印最终搜索结果列表到文件 +/// +/// 文件路径 +/// 成功与否 +int printResultListToFile(const char* filePath) +{ + FILE* memDebugFile = fopen(filePath, "a");//追加模式打开 + if (memDebugFile != NULL) { + struct timeval tv; + struct tm* tm_info; + char timeString[100]; + + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + + strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tm_info); + fprintf(memDebugFile, "\n\n\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "[LogName] 日志名称:内存搜索结果列表\n"); + fprintf(memDebugFile, "[ABI] 处理器:%s\n", ABI); + fprintf(memDebugFile, "[PackName] 进程包名:%s\n", packName); + fprintf(memDebugFile, "[PID] 进程ID:%d\n", pid); + fprintf(memDebugFile, "[PID] 搜索内存:%s\n", getMemoryAreaName()); + fprintf(memDebugFile, "[RCount] 搜索结果数量:%d\n", outcomeList.size()); + fprintf(memDebugFile, "[AddTime] 日志生成时间:%s.%ld\n", timeString, tv.tv_usec); + fprintf(memDebugFile, "[Source] 来源:ByteCat-MemTool ^O^\n"); + fprintf(memDebugFile, "ByteCat:以下数据仅用于内存分析和调试,请勿用于违法用途!\n"); + fprintf(memDebugFile, "ByteCat: The above data is only used for memory analysis and debugging, please do not use it for illegal purposes!\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "[Debug] Log format: Timestamp | Memory Area | Memory Address | DWORD Data | FLOAT Data | DOUBLE Data | WORD Data | BYTE Data | QWORD Data | Mem Map\n"); + fprintf(memDebugFile, "[调试] 日志格式: 时间戳 | 内存区域 | 内存地址 | DWORD类型数据 | FLOAT类型数据 | DOUBLE类型数据 | WORD类型数据 | BYTE类型数据 | QWORD类型数据 | 内存映射\n"); + for (int i = 0; i < outcomeList.size(); i++) + { + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tm_info); + char* mapLine = getMemoryAddrMapLine(outcomeList[i]); + fprintf(memDebugFile, "%s.%06ld 📍 内存区域:%s 内存地址:0x%lX D类型:%s F类型:%s E类型:%s W类型:%s B类型:%s Q类型:%s 📑 内存映射:%s\n", timeString, tv.tv_usec, + getMapLineMemoryAreaName(mapLine), + outcomeList[i], + getMemoryAddrData(outcomeList[i], TYPE_DWORD), + getMemoryAddrData(outcomeList[i], TYPE_FLOAT), + getMemoryAddrData(outcomeList[i], TYPE_DOUBLE), + getMemoryAddrData(outcomeList[i], TYPE_WORD), + getMemoryAddrData(outcomeList[i], TYPE_BYTE), + getMemoryAddrData(outcomeList[i], TYPE_QWORD), + mapLine); + } + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "注:以上数据仅用于内存分析和调试,请勿用于违法用途!\n"); + fprintf(memDebugFile, "Note: The above data is only used for memory analysis and debugging, please do not use it for illegal purposes!\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fclose(memDebugFile); + return 0; + } + + return -1; +} + +/// +/// 清空最终搜索结果列表 +/// +int clearResultList() +{ + if (outcomeList.empty()) { + //空列表不做操作 + return -1; + } + //清空搜索结果列表 + outcomeList.clear(); + // 释放内存 + std::vector().swap(outcomeList); + return 0; +} + +/// +/// 内存保护二次修改 +/// +void MemoryProtect(unsigned long addr){ +Protection Memory; + Memory.addr = addr; + ProtectList.push_back(Memory); +} +/// +/// 获取保护项目数量 +/// +/// 数量 +int getProtectionNum() { + return ProtectList.size(); +} +/// +/// 设置冻结修改延迟【毫秒】 +/// +/// 延迟[MS] +void setFreezeDelayMs(uint32_t delay) { + freezeDelay = delay; +} + +/// +/// 获取冻结修改项目列表 +/// +/// 冻结修改项目列表 +vector < Item > getFreezeList() { + return FreezeList; +} + +/// +/// 获取冻结修改项目数量 +/// +/// 数量 +int getFreezeNum() { + return FreezeList.size(); +} + +/// +/// 添加一个冻结修改项目 +/// +/// 修改值 +/// 内存地址 +/// 数据类型 +int addFreezeItem(const char* value, unsigned long addr, int type) +{ + //检查冻结修改项目列表是否已经存在此内存地址,防止重复添加冻结修改项目 + for (int i = 0; i < FreezeList.size(); i++) + { + if (addr == FreezeList[i].addr) + { + return -1; + } + } + Item table; + table.value = strdup(value); + table.addr = addr; + table.type = type; + FreezeList.push_back(table); + return 0; +} + +/// +/// 移除一个冻结修改项目 +/// +/// 内存地址 +int removeFreezeItem(unsigned long addr) +{ + for (int i = 0; i < FreezeList.size(); i++) + { + if (addr == FreezeList[i].addr) + { + FreezeList.erase(FreezeList.begin() + i); + return 0; + } + } + return -1; +} + +/// +/// 移除所有冻结修改项目 +/// +int removeAllFreezeItem() { + if (FreezeList.empty()) { + //空列表不做操作 + return -1; + } + // 清除所有数据 + FreezeList.clear(); + // 释放内存 + std::vector().swap(FreezeList); + return 0; +} + +/// +/// 冻结循环修改线程 +/// +/// +/// +void* freezeThread(void* arg) +{ + unsigned long alignedAddr; + void* addrToProtect; + for (;;) + { + if (isInit) { + //如果需要结束冻结或者冻结列表没有冻结项目则结束 + if (!isFreeze || FreezeList.size() == 0) + { + stopAllFreeze(); + break; + } + //每轮冻结才打开mem为了提升性能而不是在每次修改时都打开mem 避免频繁IO + int fd = open(memPath, O_RDWR | O_SYNC); + if (fd >= 0) { + //遍历 内存修改 冻结列表的所有项目 + for (int i = 0; i < FreezeList.size(); i++) + { + int pageSize = getpagesize(); +if(isSecureWrites){ +addrToProtect = (void*)(FreezeList[i].addr); +alignedAddr = (unsigned long)addrToProtect & ~(pageSize - 1); } + + + switch (FreezeList[i].type) + { + + case TYPE_DWORD: + { + DWORD v = atoi(FreezeList[i].value); + + pwrite64(fd, &v, sizeof(DWORD), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + + } + break; + case TYPE_FLOAT: + { + FLOAT v = atof(FreezeList[i].value); + + + pwrite64(fd, &v, sizeof(FLOAT), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize,PROT_WRITE | PROT_EXEC); + } + + break; + case TYPE_DOUBLE: + { + DOUBLE v = strtod(FreezeList[i].value, NULL); + + + pwrite64(fd, &v, sizeof(DOUBLE), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize,PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_QWORD: + { + QWORD v = atoll(FreezeList[i].value); + + + pwrite64(fd, &v, sizeof(QWORD), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize,PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_WORD: + { + WORD v = (WORD)atoi(FreezeList[i].value); + + + pwrite64(fd, &v, sizeof(WORD), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize, PROT_WRITE | PROT_EXEC); + } + break; + case TYPE_BYTE: + { + BYTE v = (BYTE)atoi(FreezeList[i].value); + + + pwrite64(fd, &v, sizeof(BYTE), FreezeList[i].addr); + int res = mprotect((void*)alignedAddr, pageSize,PROT_WRITE | PROT_EXEC); + } + break; + } + } + close(fd); + } + //延迟 + if (freezeDelay != 0) { + usleep(freezeDelay * 1000);//转换为微秒 + } + } + + } + return NULL; +} + +/// +/// 开始所有冻结修改项目 +/// +int startAllFreeze() +{ + if (!isInit) { + //没有进行初始化 + return -1; + } + if (!isFreeze) + { + //冻结列表有项目才开冻结线程 + if (FreezeList.size() > 0) + { + isFreeze = true;//正在冻结 + //开始启动冻结线程 + pthread_t t; + pthread_create(&t, NULL, freezeThread, NULL); + return 0; + } + } + return -1; +} + +/// +/// 停止所有冻结修改项目 +/// +int stopAllFreeze() +{ + if (isFreeze) + { + isFreeze = false; + return 0; + } + return -1; +} + +/// +/// 打印冻结列表到指定文件 +/// +/// 文件绝对路径 +/// 成功与否 +int printFreezeListToFile(const char* filePath) +{ + FILE* memDebugFile = fopen(filePath, "a");//追加模式打开 + if (memDebugFile != NULL) { + struct timeval tv; + struct tm* tm_info; + char timeString[100]; + + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + + strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tm_info); + fprintf(memDebugFile, "\n\n\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "[LogName] 日志名称:冻结修改列表\n"); + fprintf(memDebugFile, "[ABI] 处理器:%s\n", ABI); + fprintf(memDebugFile, "[PackName] 进程包名:%s\n", packName); + fprintf(memDebugFile, "[PID] 进程ID:%d\n", pid); + fprintf(memDebugFile, "[RCount] 冻结修改数量:%d\n", FreezeList.size()); + fprintf(memDebugFile, "[AddTime] 日志生成时间:%s.%ld\n", timeString, tv.tv_usec); + fprintf(memDebugFile, "[Source] 来源:ByteCat-MemTool ^O^\n"); + fprintf(memDebugFile, "ByteCat:以下数据仅用于内存分析和调试,请勿用于违法用途!\n"); + fprintf(memDebugFile, "ByteCat: The above data is only used for memory analysis and debugging, please do not use it for illegal purposes!\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "[Debug] Log format: [❄ Freeze info] Timestamp | Memory Area | Memory Address | DWORD Data | FLOAT Data | DOUBLE Data | WORD Data | BYTE Data | QWORD Data | Mem Map\n"); + fprintf(memDebugFile, "[调试] 日志格式: [❄ 冻结信息] 时间戳 | 内存区域 | 内存地址 | DWORD类型数据 | FLOAT类型数据 | DOUBLE类型数据 | WORD类型数据 | BYTE类型数据 | QWORD类型数据 | 内存映射\n"); + for (int i = 0; i < FreezeList.size(); i++) + { + gettimeofday(&tv, NULL); + tm_info = localtime(&tv.tv_sec); + strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tm_info); + char* mapLine = getMemoryAddrMapLine(FreezeList[i].addr); + fprintf(memDebugFile, "%s.%06ld 【❄ 修改值:%s 修改类型:%s】 📍 内存区域:%s 内存地址:0x%lX D类型:%s F类型:%s E类型:%s W类型:%s B类型:%s Q类型:%s 📑 内存映射:%s\n", timeString, tv.tv_usec, + FreezeList[i].value, + getDataTypeName(FreezeList[i].type), + getMapLineMemoryAreaName(mapLine), + FreezeList[i].addr, + getMemoryAddrData(FreezeList[i].addr, TYPE_DWORD), + getMemoryAddrData(FreezeList[i].addr, TYPE_FLOAT), + getMemoryAddrData(FreezeList[i].addr, TYPE_DOUBLE), + getMemoryAddrData(FreezeList[i].addr, TYPE_WORD), + getMemoryAddrData(FreezeList[i].addr, TYPE_BYTE), + getMemoryAddrData(FreezeList[i].addr, TYPE_QWORD), + mapLine); + } + fprintf(memDebugFile, "======================================================================================================================\n"); + fprintf(memDebugFile, "注:以上数据仅用于内存分析和调试,请勿用于违法用途!\n"); + fprintf(memDebugFile, "Note: The above data is only used for memory analysis and debugging, please do not use it for illegal purposes!\n"); + fprintf(memDebugFile, "======================================================================================================================\n"); + fclose(memDebugFile); + return 0; + } + + return -1; +} + +/// +/// 获取指定内存地址的maps映射行 +/// +/// 内存地址 +/// maps映射行 +char* getMemoryAddrMapLine(unsigned long address) { + if (!isInit) { + return "NULL"; + } + //存储映射信息 + unsigned long start, end, offset; + char perms[5], dev[6], path[1024]; + int inode; + + FILE* file; //maps文件指针 + char line[4096]; //存储读取到的一行数据 + + file = fopen(mapsPath, "r"); + if (file) { + //逐行读取maps文件内容 + while (fgets(line, sizeof(line), file)) { + + sscanf(line, "%lx-%lx %4s %lx %5s %d %[^\n]", + &start, &end, perms, &offset, dev, &inode, path); + //如果给定的地址在当前行描述的内存区域范围内 + if (address >= start && address < end) { + fclose(file); // 关闭文件 + return line;//返回映射行 + } + } + fclose(file); // 关闭文件 + } + return "NULL"; +} + +/// +/// 获取Maps映射行所在内存区域名称 +/// +/// +/// 内存名称字符串 +char* getMapLineMemoryAreaName(const char* mapLine) { + //jh和j 模拟器cd和xa + + if (BCMAPSFLAG(mapLine, RANGE_C_HEAP)) { + return "C堆内存 [Ch: C++ heap]"; + } + if (BCMAPSFLAG(mapLine, RANGE_C_ALLOC)) { + return "C分配内存 [Ca: C++ alloc]"; + } + if (BCMAPSFLAG(mapLine, RANGE_C_BSS)) { + return "C未初始化数据 [Cb: C++ .bss]"; + } + if (BCMAPSFLAG(mapLine, RANGE_ANONYMOUS)) { + return "匿名内存 [A: Anonymous]"; + } + if (BCMAPSFLAG(mapLine, RANGE_STACK)) { + return "栈内存 [S: Stack]"; + } + if (BCMAPSFLAG(mapLine, RANGE_ASHMEM)) { + return "Android共享内存 [As: Ashmem]"; + } + if (BCMAPSFLAG(mapLine, RANGE_VIDEO)) { + //BCMEM_LOGI("此内存有错误"); + return "视频内存 [V: Video]"; + } + if (BCMAPSFLAG(mapLine, RANGE_B_BAD)) { + //BCMEM_LOGI("此内存有错误"); + return "错误内存 [B: Bad]"; + } + if (BCMAPSFLAG(mapLine, RANGE_CODE_SYSTEM)) { + return "系统代码 [Xs: Code system]"; + } + + //j内存和jh内存筛选特征相同 + /*if (BCMAPSFLAG(mapLine, RANGE_JAVA_HEAP)) { + return "Java虚拟机堆内存 [Jh: Java heap]"; + }*/ + if (BCMAPSFLAG(mapLine, RANGE_JAVA)) { + return "Java内存 [J: Java] 或 Java虚拟机堆内存 [Jh: Java heap]"; + } + + //cd和xa在模拟器可能错误 因此针对 +#if defined(__arm__) || defined(__aarch64__) //arm32和arm64架构 + if (BCMAPSFLAG(mapLine, RANGE_C_DATA)) { + return "C数据内存 [Cd: C++ .data]"; + } + if (BCMAPSFLAG(mapLine, RANGE_CODE_APP)) { + return "应用程序代码 [Xa: Code app]"; + } +#else//x86和x64架构 针对模拟器 + if (BCMAPSFLAG(mapLine, RANGE_C_DATA)) { + return "C数据内存 [Cd: C++ .data] 或 应用程序代码 [Xa: Code app]"; + } + if (BCMAPSFLAG(mapLine, RANGE_CODE_APP)) { + return "应用程序代码 [Xa: Code app]"; + } +#endif + + + //if (BCMAPSFLAG(mapLine, RANGE_OTHER)) { + // //BCMEM_LOGI("此内存有错误,无法完全排除"); + // return "其他内存 [O: Other]"; + //} + + //以上都不是则在O + return "其他内存 [O: Other]"; +} + + +/// +/// 获取指定id的内存名称 +/// +/// 内存id +/// 内存名称字符串 +char* getMemoryAreaIdName(int memid) { + if (memid == RANGE_ALL) { + return "所有内存 [ALL]"; + } + if (memid == RANGE_JAVA_HEAP) { + return "Java虚拟机堆内存 [Jh: Java heap]"; + } + if (memid == RANGE_C_HEAP) { + return "C堆内存 [Ch: C++ heap]"; + } + if (memid == RANGE_C_ALLOC) { + return "C分配内存 [Ca: C++ alloc]"; + } + if (memid == RANGE_C_DATA) { + return "C数据内存 [Cd: C++ .data]"; + } + if (memid == RANGE_C_BSS) { + return "C未初始化数据 [Cb: C++ .bss]"; + } + if (memid == RANGE_ANONYMOUS) { + return "匿名内存 [A: Anonymous]"; + } + if (memid == RANGE_JAVA) { + return "Java内存 [J: Java]"; + } + if (memid == RANGE_STACK) { + return "栈内存 [S: Stack]"; + } + if (memid == RANGE_ASHMEM) { + return "Android共享内存 [As: Ashmem]"; + } + if (memid == RANGE_VIDEO) { + //BCMEM_LOGI("此内存有错误"); + return "视频内存 [V: Video]"; + } + if (memid == RANGE_OTHER) { + //BCMEM_LOGI("此内存有错误,无法完全排除"); + return "其他内存 [O: Other]"; + } + if (memid == RANGE_B_BAD) { + //BCMEM_LOGI("此内存有错误"); + return "错误内存 [B: Bad]"; + } + if (memid == RANGE_CODE_APP) { + return "应用程序代码 [Xa: Code app]"; + } + if (memid == RANGE_CODE_SYSTEM) { + return "系统代码 [Xs: Code system]"; + } + + return "未知内存 [NULL]"; +} +/// +/// 获取当前内存名称 +/// +/// 内存名称字符串 +char* getMemoryAreaName() { + return getMemoryAreaIdName(memory); +} + +/// +/// 获取数据类型名称 +/// +/// 类型id +/// 类型名称字符串 +char* getDataTypeName(int typeId) { + switch (typeId) + { + case TYPE_DWORD: + { + return "DWORD-32位有符号整数 [D: int32_t]"; + } + break; + case TYPE_FLOAT: + { + return "FLOAT-单精度浮点数 [F: float]"; + } + break; + case TYPE_DOUBLE: + { + return "DOUBLE-双精度浮点数 [E: double]"; + } + break; + case TYPE_QWORD: + { + return "QWORD-64位有符号整数 [Q: int64_t]"; + } + break; + case TYPE_WORD: + { + return "WORD-有符号短整型 [W: signed short]"; + } + break; + case TYPE_BYTE: + { + return "BYTE-有符号字符 [B: signed char]"; + } + break; + default: + { + return "未知类型 [NULL]"; + } + break; + } +} + +/// +/// 杀掉指定包名的进程 +/// +/// 进程APK包名 +/// 成功与否 +int killProcess_Root(const char* packageName) +{ + int pid = getPID(packageName); //获取进程ID + if (pid == -1) + { + return -1; + } + + //SIGTERM信号杀死进程 + if (kill(pid, SIGTERM) == -1) { + return -1; + } + + return 0; //成功 +} + +/// +/// 暂停指定包名的进程 +/// +/// 进程包名 +/// 成功与否 +int stopProcess_Root(const char* packageName) { + int pid = getPID(packageName); + if (pid == -1) { + return -1; + } + + //SIGSTOP信号暂停进程 + if (kill(pid, SIGSTOP) == -1) { + return -1; + } + return 0; //成功 +} + +/// +/// 恢复被暂停的指定包名的进程 +/// +/// 进程包名 +/// 成功与否 +int resumeProcess_Root(const char* packageName) { + int pid = getPID(packageName); + if (pid == -1) { + return -1; + } + + //SIGCONT信号恢复被暂停的进程 + if (kill(pid, SIGCONT) == -1) { + return -1; + } + return 0; //成功 +} +/// +/// 杀死所有inotify,防止游戏监视文件变化 +/// +void killAllInotify_Root() +{ + //通过将内核inotify文件监视器的最大数量设置为0 这样就可以禁用所有inotify + system("echo 0 > /proc/sys/fs/inotify/max_user_watches"); +} + +/// +/// 杀死GG修改器进程 +/// +/// 杀死的进程数量 +int killGG_Root() +{ + DIR* dir = NULL; //指向目录流的指针 + DIR* dirGG = NULL; //指向子目录流的指针 + struct dirent* ptr = NULL; //目录项结构体,用于存储目录中的条目 + struct dirent* ptrGG = NULL; //目录项结构体,用于存储子目录中的条目 + char filepath[256]; //存储文件路径 + int num = 0;// 数量 + + dir = opendir("/data/data"); + if (dir != NULL) { + //检测data目录下每一个包名文件夹下是否为GG修改器 + while ((ptr = readdir(dir)) != NULL) + { + //跳过"."和".."目录和文件 + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0) || (ptr->d_type != DT_DIR)) { + continue; + } + + //生成当前包名的files文件夹的完整路径 + sprintf(filepath, "/data/data/%s/files", ptr->d_name); + dirGG = opendir(filepath); //打开files + if (dirGG != NULL) + { + while ((ptrGG = readdir(dirGG)) != NULL) + { + // 跳过"."和".."目录和文件 + if ((strcmp(ptrGG->d_name, ".") == 0) || (strcmp(ptrGG->d_name, "..") == 0) || (ptrGG->d_type != DT_DIR)) { + continue; + } + + if (strstr(ptrGG->d_name, "GG")) + { + //杀掉GG进程 + killProcess_Root(ptr->d_name); + num++;// 成功杀死一个GG进程 + } + } + closedir(dirGG); + } + } + closedir(dir); + } + return num;// 返回杀死的进程数量 +} + +/// +/// 杀死XS脚本进程 +/// +/// 杀死的进程数量 +int killXscript_Root() { + DIR* dir = NULL; // 目录流指针,用于打开目录 + DIR* dirXS = NULL; // 目录流指针,用于打开目录 + struct dirent* ptr = NULL; // 目录项指针,用于读取目录项 + struct dirent* ptrXS = NULL; // 存储lib文件夹当前目录项 + char filepath[256]; // 存储文件路径的缓冲区 + int num = 0;// 数量 + + // 打开目录 "/data/data" + dir = opendir("/data/data"); + + if (dir != NULL) { + // 循环读取目录下的每一个文件/文件夹 + while ((ptr = readdir(dir)) != NULL) { + //跳过"."和".."目录和文件 + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0) || (ptr->d_type != DT_DIR)) { + continue; + } + + // 生成要读取的文件的路径 + sprintf(filepath, "/data/data/%s/lib", ptr->d_name); + // 打开这个文件夹 + dirXS = opendir(filepath); + if (dirXS != NULL) + { + //读取lib文件夹每一个文件 + while ((ptrXS = readdir(dirXS)) != NULL) + { + //如果动态库名称包含xs脚本则杀死 + if (strstr(ptrXS->d_name, "libxscript")) + { + //杀掉这个XS进程 + killProcess_Root(ptr->d_name); + num++;//成功杀死一个XS进程 + } + } + closedir(dirXS); + } + } + // 关闭目录流 + closedir(dir); + } + return num;//返回杀死的进程数量 +} + + +/// +/// 重启手机 +/// +/// 成功与否 +int rebootsystem_Root() +{ + return system("su -c 'reboot'"); +} +/// +/// 静默安装 指定路径的APK安装包 +/// +/// apk安装包路径 +/// 成功与否 +int installapk_Root(const char* apkPackagePath) +{ + char ml[256]; + sprintf(ml, "pm install %s", apkPackagePath); + return system(ml); +} +/// +/// 静默卸载 指定包名的APK软件 +/// +/// APK包名 +/// 成功与否 +int uninstallapk_Root(const char* packageName) +{ + char ml[256]; + sprintf(ml, "pm uninstall %s", packageName); + return system(ml); +} +/// +/// 执行命令 +/// +/// 命令 +/// 执行状态 +int Cmd(const char* command) { + int status = system(command); + return WEXITSTATUS(status); +} +/// +/// 执行超级命令 +/// +/// 命令 +/// 执行状态 +int Cmd_Root(const char* command) { + // 创建一个完整的命令字符串 + char fullCommand[256]; + snprintf(fullCommand, sizeof(fullCommand), "su -c '%s'", command); + int status = system(fullCommand); + return WEXITSTATUS(status); +} + diff --git a/app/src/main/jni/AlguiMemTool_jni.h b/app/src/main/jni/AlguiMemTool_jni.h new file mode 100644 index 0000000..586e67c --- /dev/null +++ b/app/src/main/jni/AlguiMemTool_jni.h @@ -0,0 +1,409 @@ +#pragma once +#include +#include "AlguiMemTool.h" +//AlguiMemTool.h - 对接到Java的 JNI 接口 +//作者:ByteCat 作者QQ:3353484607 游戏逆向交流QQ群:931212209 +extern "C" { + + // 设置目标包名 【注意:这是初始化函数,不调用此函数的话其它内存操作均失效】 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_setPackageName(JNIEnv* env, jobject obj, jstring packageName) { + const char* nativePackageName = env->GetStringUTFChars(packageName, 0); + int result = setPackageName(nativePackageName); + env->ReleaseStringUTFChars(packageName, nativePackageName); + return result; + } + // 获取进程ID + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getPID(JNIEnv* env, jobject obj, jstring packageName) { + const char* nativePackageName = env->GetStringUTFChars(packageName, 0); + int result = getPID(nativePackageName); + env->ReleaseStringUTFChars(packageName, nativePackageName); + return result; + } + // 设置安全写入启用状态 + JNIEXPORT void JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_setIsSecureWrites(JNIEnv* env, jobject obj, jboolean sw) { + setIsSecureWrites(sw); + } + + + // 获取模块起始地址(基址) + JNIEXPORT jlong JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getModuleBaseAddr(JNIEnv* env, jobject obj, jstring moduleName, jint headType) { + const char* nativeModuleName = env->GetStringUTFChars(moduleName, 0); + unsigned long result = getModuleBaseAddr(nativeModuleName, headType); + env->ReleaseStringUTFChars(moduleName, nativeModuleName); + return result; + } + // 跳转指针 + JNIEXPORT jlong JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_jump(JNIEnv* env, jobject obj, jlong addr,jint count) { + return jump(addr,count); + } + // 跳转指针 [32位] + JNIEXPORT jlong JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_jump32(JNIEnv* env, jobject obj, jlong addr) { + return jump32(addr); + } + // 跳转指针 [64位] + JNIEXPORT jlong JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_jump64(JNIEnv* env, jobject obj, jlong addr) { + return jump64(addr); + } + // 设置指定内存地址指向的值 🛡️该方法已对当前进程进行保护 防止GG模糊🛡️ + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_setMemoryAddrValue(JNIEnv* env, jobject obj, jstring value, jlong addr, jint type, jboolean isFree,jboolean isSecure) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + int result = setMemoryAddrValue(nativeValue, addr, type, isFree,isSecure); + env->ReleaseStringUTFChars(value, nativeValue); + return result; + } + // 获取指定内存地址的数据 + JNIEXPORT jstring JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getMemoryAddrData(JNIEnv* env, jobject obj, jlong addr, jint type) { + char* result = getMemoryAddrData(addr, type); + jstring javaString = env->NewStringUTF(result); + return javaString; + } + + + + // 设置要搜索的内存区域 + JNIEXPORT void JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_setMemoryArea + (JNIEnv* env, jobject obj, jint memoryArea) { + setMemoryArea(memoryArea); + } + // 内存搜索 + JNIEXPORT jlongArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_MemorySearch + (JNIEnv* env, jobject obj, jstring value, jint type) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + std::vector results = MemorySearch(nativeValue, type); + env->ReleaseStringUTFChars(value, nativeValue); + + jlongArray resultArray = env->NewLongArray(results.size()); + jlong* arrayElements = new jlong[results.size()]; + for (size_t i = 0; i < results.size(); ++i) { + arrayElements[i] = static_cast(results[i]); + } + env->SetLongArrayRegion(resultArray, 0, results.size(), arrayElements); + delete[] arrayElements; + return resultArray; + } + // 内存搜索范围值 + JNIEXPORT jlongArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_MemorySearchRange + (JNIEnv* env, jobject obj, jstring value, jint type) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + std::vector results = MemorySearchRange(nativeValue, type); + env->ReleaseStringUTFChars(value, nativeValue); + + jlongArray resultArray = env->NewLongArray(results.size()); + jlong* arrayElements = new jlong[results.size()]; + for (size_t i = 0; i < results.size(); ++i) { + arrayElements[i] = static_cast(results[i]); + } + env->SetLongArrayRegion(resultArray, 0, results.size(), arrayElements); + delete[] arrayElements; + return resultArray; + } + // 联合内存搜索 + JNIEXPORT jlongArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_MemorySearchUnited + (JNIEnv* env, jobject obj, jstring value, jint type) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + std::vector results = MemorySearchUnited(nativeValue, type); + env->ReleaseStringUTFChars(value, nativeValue); + + jlongArray resultArray = env->NewLongArray(results.size()); + jlong* arrayElements = new jlong[results.size()]; + for (size_t i = 0; i < results.size(); ++i) { + arrayElements[i] = static_cast(results[i]); + } + env->SetLongArrayRegion(resultArray, 0, results.size(), arrayElements); + delete[] arrayElements; + return resultArray; + } + // 偏移改善结果 + JNIEXPORT jlongArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_ImproveOffset + (JNIEnv* env, jobject obj, jstring value, jint type, jlong offset) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + std::vector results = ImproveOffset(nativeValue, type, static_cast(offset)); + env->ReleaseStringUTFChars(value, nativeValue); + + jlongArray resultArray = env->NewLongArray(results.size()); + jlong* arrayElements = new jlong[results.size()]; + for (size_t i = 0; i < results.size(); ++i) { + arrayElements[i] = static_cast(results[i]); + } + env->SetLongArrayRegion(resultArray, 0, results.size(), arrayElements); + delete[] arrayElements; + return resultArray; + } + // 偏移范围改善结果 + JNIEXPORT jlongArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_ImproveOffsetRange + (JNIEnv* env, jobject obj, jstring value, jint type, jlong offset) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + std::vector results = ImproveOffsetRange(nativeValue, type, static_cast(offset)); + env->ReleaseStringUTFChars(value, nativeValue); + + jlongArray resultArray = env->NewLongArray(results.size()); + jlong* arrayElements = new jlong[results.size()]; + for (size_t i = 0; i < results.size(); ++i) { + arrayElements[i] = static_cast(results[i]); + } + env->SetLongArrayRegion(resultArray, 0, results.size(), arrayElements); + delete[] arrayElements; + return resultArray; + } + // 偏移联合改善结果 + JNIEXPORT jlongArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_ImproveOffsetUnited + (JNIEnv* env, jobject obj, jstring value, jint type, jlong offset) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + std::vector results = ImproveOffsetUnited(nativeValue, type, static_cast(offset)); + env->ReleaseStringUTFChars(value, nativeValue); + + jlongArray resultArray = env->NewLongArray(results.size()); + jlong* arrayElements = new jlong[results.size()]; + for (size_t i = 0; i < results.size(); ++i) { + arrayElements[i] = static_cast(results[i]); + } + env->SetLongArrayRegion(resultArray, 0, results.size(), arrayElements); + delete[] arrayElements; + return resultArray; + } + // 直接改善结果 + JNIEXPORT jlongArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_ImproveValue + (JNIEnv* env, jobject obj, jstring value, jint type) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + std::vector results = ImproveValue(nativeValue, type); + env->ReleaseStringUTFChars(value, nativeValue); + + jlongArray resultArray = env->NewLongArray(results.size()); + jlong* arrayElements = new jlong[results.size()]; + for (size_t i = 0; i < results.size(); ++i) { + arrayElements[i] = static_cast(results[i]); + } + env->SetLongArrayRegion(resultArray, 0, results.size(), arrayElements); + delete[] arrayElements; + return resultArray; + } + // 结果偏移写入数据 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_MemoryOffsetWrite + (JNIEnv* env, jobject obj, jstring value, jint type, jlong offset, jboolean isFree,jboolean isSecure) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + int result = MemoryOffsetWrite(nativeValue, type, static_cast(offset), isFree,isSecure); + env->ReleaseStringUTFChars(value, nativeValue); + return result; + } + // 获取最终搜索结果数量 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getResultCount + (JNIEnv* env, jobject obj) { + return getResultCount(); + } + // 获取最终搜索结果列表 + JNIEXPORT jlongArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getResultList + (JNIEnv* env, jobject obj) { + std::vector results = getResultList(); + jlongArray resultArray = env->NewLongArray(results.size()); + jlong* arrayElements = new jlong[results.size()]; + for (size_t i = 0; i < results.size(); ++i) { + arrayElements[i] = static_cast(results[i]); + } + env->SetLongArrayRegion(resultArray, 0, results.size(), arrayElements); + delete[] arrayElements; + return resultArray; + } + // 打印最终搜索结果列表到指定文件 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_printResultListToFile + (JNIEnv* env, jobject obj, jstring filePath) { + const char* nativeFilePath = env->GetStringUTFChars(filePath, 0); + int result = printResultListToFile(nativeFilePath); + env->ReleaseStringUTFChars(filePath, nativeFilePath); + return result; + } + // 清空最终搜索结果列表 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_clearResultList + (JNIEnv* env, jobject obj) { + return clearResultList(); + } + + + + + // 获取冻结修改项目列表 【Java需要自行创建Item类再创建列表接收】 + JNIEXPORT jobjectArray JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getFreezeList(JNIEnv* env, jobject obj) { + vector freezeList = getFreezeList(); + jclass freezeItemClass = env->FindClass("irene/window/algui/Item"); + jmethodID constructor = env->GetMethodID(freezeItemClass, "", "(Ljava/lang/String;J.I)V"); + jobjectArray result = env->NewObjectArray(freezeList.size(), freezeItemClass, NULL); + + for (size_t i = 0; i < freezeList.size(); ++i) { + Item& item = freezeList[i]; + jstring value = env->NewStringUTF(item.value); + jobject freezeItemObj = env->NewObject(freezeItemClass, constructor, value, item.addr, item.type); + env->SetObjectArrayElement(result, i, freezeItemObj); + } + + return result; + } + // 设置冻结修改延迟 + JNIEXPORT void JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_setFreezeDelayMs(JNIEnv* env, jobject obj, jint delay) { + setFreezeDelayMs(static_cast(delay)); + } + // 获取冻结修改项目数量 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getFreezeNum(JNIEnv* env, jobject obj) { + return static_cast(getFreezeNum()); + } + // 添加一个冻结修改项目 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_addFreezeItem(JNIEnv* env, jobject obj, jstring value, jlong addr, jint type) { + const char* nativeValue = env->GetStringUTFChars(value, 0); + int result = addFreezeItem(nativeValue, static_cast(addr), static_cast(type)); + env->ReleaseStringUTFChars(value, nativeValue); + return static_cast(result); + } + // 移除一个冻结修改项目 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_removeFreezeItem(JNIEnv* env, jobject obj, jlong addr) { + return static_cast(removeFreezeItem(static_cast(addr))); + } + // 移除所有冻结修改项目 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_removeAllFreezeItem(JNIEnv* env, jobject obj) { + return static_cast(removeAllFreezeItem()); + } + // 冻结循环修改线程忽略$ + // + // 开始冻结所有修改项目 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_startAllFreeze(JNIEnv* env, jobject obj) { + return static_cast(startAllFreeze()); + } + // 停止冻结所有修改项目 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_stopAllFreeze(JNIEnv* env, jobject obj) { + return static_cast(stopAllFreeze()); + } + // 打印冻结列表到指定文件 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_printFreezeListToFile(JNIEnv* env, jobject obj, jstring filePath) { + const char* nativeFilePath = env->GetStringUTFChars(filePath, 0); + int result = printFreezeListToFile(nativeFilePath); + env->ReleaseStringUTFChars(filePath, nativeFilePath); + return static_cast(result); + } + + + + // 获取指定内存地址的Maps映射行 + JNIEXPORT jstring JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getMemoryAddrMapLine + (JNIEnv* env, jobject obj, jlong address) { + char* result = getMemoryAddrMapLine(static_cast(address)); + jstring jResult = env->NewStringUTF(result); + return jResult; + } + // 获取Maps映射行所在内存区域名称 + JNIEXPORT jstring JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getMapLineMemoryAreaName + (JNIEnv* env, jobject obj, jstring mapLine) { + const char* nativeMapLine = env->GetStringUTFChars(mapLine, 0); + char* result = getMapLineMemoryAreaName(nativeMapLine); + jstring jResult = env->NewStringUTF(result); + env->ReleaseStringUTFChars(mapLine, nativeMapLine); + return jResult; + } + // 获取指定内存id的内存名称 + JNIEXPORT jstring JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getMemoryAreaIdName + (JNIEnv* env, jobject obj, jint memid) { + char* result = getMemoryAreaIdName(static_cast(memid)); + jstring jResult = env->NewStringUTF(result); + return jResult; + } + // 获取当前内存名称 + JNIEXPORT jstring JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getMemoryAreaName + (JNIEnv* env, jobject obj) { + char* result = getMemoryAreaName(); + jstring jResult = env->NewStringUTF(result); + return jResult; + } + // 获取指定数据类型id的数据类型名称 + JNIEXPORT jstring JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getDataTypeName + (JNIEnv* env, jobject obj, jint typeId) { + char* result = getDataTypeName(static_cast(typeId)); + jstring jResult = env->NewStringUTF(result); + return jResult; + } + + + + + // 杀掉指定包名的进程 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_killProcess_1Root + (JNIEnv* env, jobject obj, jstring packageName) { + const char* nativePackageName = env->GetStringUTFChars(packageName, 0); + int result = killProcess_Root(nativePackageName); + env->ReleaseStringUTFChars(packageName, nativePackageName); + return result; + } + // 暂停指定包名的进程 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_stopProcess_1Root(JNIEnv* env, jobject obj, jstring packageName) { + const char* nativePackageName = env->GetStringUTFChars(packageName, 0); + int result = stopProcess_Root(nativePackageName); + env->ReleaseStringUTFChars(packageName, nativePackageName); + return result; + } + // 恢复被暂停的指定包名的进程 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_resumeProcess_1Root(JNIEnv* env, jobject obj, jstring packageName) { + const char* nativePackageName = env->GetStringUTFChars(packageName, 0); + int result = resumeProcess_Root(nativePackageName); + env->ReleaseStringUTFChars(packageName, nativePackageName); + return result; + } + // 杀掉所有inotify监视器,防止游戏监视文件变化 + JNIEXPORT void JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_killAllInotify_1Root + (JNIEnv* env, jobject obj) { + killAllInotify_Root(); + } + // 杀掉GG修改器 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_killGG_1Root + (JNIEnv* env, jobject obj) { + return killGG_Root(); + } + // 杀掉XS脚本 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_killXscript_1Root + (JNIEnv* env, jobject obj) { + return killXscript_Root(); + } + // 重启手机 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_rebootsystem_1Root + (JNIEnv* env, jobject obj) { + return rebootsystem_Root(); + } + // 静默安装指定路径的APK安装包 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_installapk_1Root + (JNIEnv* env, jobject obj, jstring apkPackagePath) { + const char* nativePath = env->GetStringUTFChars(apkPackagePath, 0); + int result = installapk_Root(nativePath); + env->ReleaseStringUTFChars(apkPackagePath, nativePath); + return result; + } + // 静默卸载指定包名的APK软件 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_uninstallapk_1Root + (JNIEnv* env, jobject obj, jstring packageName) { + const char* nativePackageName = env->GetStringUTFChars(packageName, 0); + int result = uninstallapk_Root(nativePackageName); + env->ReleaseStringUTFChars(packageName, nativePackageName); + return result; + } + // 执行命令 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_Cmd + (JNIEnv* env, jobject obj, jstring packageName) { + const char* nativePackageName = env->GetStringUTFChars(packageName, 0); + int result = Cmd(nativePackageName); + env->ReleaseStringUTFChars(packageName, nativePackageName); + return result; + } + // 执行超级命令 + JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_Cmd_1Root + (JNIEnv* env, jobject obj, jstring packageName) { + const char* nativePackageName = env->GetStringUTFChars(packageName, 0); + int result = Cmd_Root(nativePackageName); + env->ReleaseStringUTFChars(packageName, nativePackageName); + return result; + } + //内存保护 +JNIEXPORT void JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_MemoryProtect + (JNIEnv *, jobject, jlong addr) { + Protection Memory; + Memory.addr = static_cast(addr); + ProtectList.push_back(Memory); +} +// JNI 实现 getProtectionNum 方法 +JNIEXPORT jint JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_getProtectionNum + (JNIEnv *, jobject) { + return static_cast(ProtectList.size()); +} +} diff --git a/app/src/main/jni/And64InlineHook/And64InlineHook.cpp b/app/src/main/jni/And64InlineHook/And64InlineHook.cpp new file mode 100644 index 0000000..aa8697b --- /dev/null +++ b/app/src/main/jni/And64InlineHook/And64InlineHook.cpp @@ -0,0 +1,616 @@ +/* + * @date : 2018/04/18 + * @author : Rprop (r_prop@outlook.com) + * https://github.com/Rprop/And64InlineHook + */ +/* +//2023/6/26 by艾琳汉化(团队:无尽的四月) 游戏MOD交流群368969530 + + 麻省理工学院执照 + + 版权所有 (c) 2018 Rprop (r_prop@outlook.com) + + 特此免费授予任何获得副本的人 + 本软件和相关文档文件(“软件”),以处理 + 在软件中不受限制,包括但不限于权利 + 使用、复制、修改、合并、发布、分发、再许可和/或出售 + 软件的副本,并允许软件所针对的人员 + 提供,但须符合以下条件: + + 上述版权声明和本许可声明应包含在所有 + 本软件的副本或大部分内容。 + + 本软件按“原样”提供,不提供任何形式的明示或保证 + 暗示,包括但不限于适销性保证, + 适用于特定目的且不侵权。在任何情况下,都不得 + 作者或版权所有者对任何索赔、损害赔偿或其他索赔、损害赔偿或其他责任 + 责任,无论是在合同、侵权或其他诉讼中,由以下原因引起: + 出于或与本软件有关,或在 + 软件。 + */ +#define __STDC_FORMAT_MACROS + +#include +#include +#include +#include +#include +#include + +#if defined(__aarch64__) + +#include "And64InlineHook.hpp" + +#define A64_MAX_INSTRUCTIONS 5 +#define A64_MAX_REFERENCES (A64_MAX_INSTRUCTIONS * 2) +#define A64_NOP 0xd503201fu +#define A64_JNIEXPORT __attribute__((visibility("hidden"))) +#define A64_LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "A64_HOOK", __VA_ARGS__)) +#ifndef NDEBUG +# define A64_LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "A64_HOOK", __VA_ARGS__)) +#else +# define A64_LOGI(...) ((void)0) +#endif // NDEBUG +typedef uint32_t *__restrict *__restrict instruction; +typedef struct { + struct fix_info { + uint32_t *bp; + uint32_t ls; // left-shift counts (左移计数) + uint32_t ad; // & operand (操作数) + }; + struct insns_info { + union { + uint64_t insu; + int64_t ins; + void *insp; + }; + fix_info fmap[A64_MAX_REFERENCES]; + }; + int64_t basep; + int64_t endp; + insns_info dat[A64_MAX_INSTRUCTIONS]; + +public: + inline bool is_in_fixing_range(const int64_t absolute_addr) { + return absolute_addr >= this->basep && absolute_addr < this->endp; + } + + inline intptr_t get_ref_ins_index(const int64_t absolute_addr) { + return static_cast((absolute_addr - this->basep) / sizeof(uint32_t)); + } + + inline intptr_t get_and_set_current_index(uint32_t *__restrict inp, uint32_t *__restrict outp) { + intptr_t current_idx = this->get_ref_ins_index(reinterpret_cast(inp)); + this->dat[current_idx].insp = outp; + return current_idx; + } + + inline void reset_current_ins(const intptr_t idx, uint32_t *__restrict outp) { + this->dat[idx].insp = outp; + } + + void + insert_fix_map(const intptr_t idx, uint32_t *bp, uint32_t ls = 0u, uint32_t ad = 0xffffffffu) { + for (auto &f : this->dat[idx].fmap) { + if (f.bp == NULL) { + f.bp = bp; + f.ls = ls; + f.ad = ad; + return; + } //if + } + // What? GGing.. + } + + void process_fix_map(const intptr_t idx) { + for (auto &f : this->dat[idx].fmap) { + if (f.bp == NULL) break; + *(f.bp) = *(f.bp) | + (((int32_t(this->dat[idx].ins - reinterpret_cast(f.bp)) >> 2) + << f.ls) & f.ad); + f.bp = NULL; + } + } +} context; + +//------------------------------------------------------------------------- + +static bool __fix_branch_imm(instruction inpp, instruction outpp, context *ctxp) { + static constexpr uint32_t mbits = 6u; + static constexpr uint32_t mask = 0xfc000000u; // 0b11111100000000000000000000000000 + static constexpr uint32_t rmask = 0x03ffffffu; // 0b00000011111111111111111111111111 + static constexpr uint32_t op_b = 0x14000000u; // "b" ADDR_PCREL26 + static constexpr uint32_t op_bl = 0x94000000u; // "bl" ADDR_PCREL26 + + const uint32_t ins = *(*inpp); + const uint32_t opc = ins & mask; + switch (opc) { + case op_b: + case op_bl: { + intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); + int64_t absolute_addr = reinterpret_cast(*inpp) + + (static_cast(ins << mbits) + >> (mbits - 2u)); // sign-extended (符号扩展) + int64_t new_pc_offset = + static_cast(absolute_addr - reinterpret_cast(*outpp)) + >> 2; // 转移 + bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); + // 是否应将分支转换为绝对跳转 + if (!special_fix_type && llabs(new_pc_offset) >= (rmask >> 1)) { + bool b_aligned = (reinterpret_cast(*outpp + 2) & 7u) == 0u; + if (opc == op_b) { + if (b_aligned != true) { + (*outpp)[0] = A64_NOP; + ctxp->reset_current_ins(current_idx, ++(*outpp)); + } //if + (*outpp)[0] = 0x58000051u; // LDR X17, #0x8 + (*outpp)[1] = 0xd61f0220u; // BR X17 + memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); + *outpp += 4; + } else { + if (b_aligned == true) { + (*outpp)[0] = A64_NOP; + ctxp->reset_current_ins(current_idx, ++(*outpp)); + } //if + (*outpp)[0] = 0x58000071u; // LDR X17, #12 + (*outpp)[1] = 0x1000009eu; // ADR X30, #16 + (*outpp)[2] = 0xd61f0220u; // BR X17 + memcpy(*outpp + 3, &absolute_addr, sizeof(absolute_addr)); + *outpp += 5; + } //if + } else { + if (special_fix_type) { + intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); + if (ref_idx <= current_idx) { + new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - + reinterpret_cast(*outpp)) + >> 2; + } else { + ctxp->insert_fix_map(ref_idx, *outpp, 0u, rmask); + new_pc_offset = 0; + } //if + } //if + + (*outpp)[0] = opc | (new_pc_offset & ~mask); + ++(*outpp); + } //if + + ++(*inpp); + return ctxp->process_fix_map(current_idx), true; + } + } + return false; +} + +//------------------------------------------------------------------------- + +static bool __fix_cond_comp_test_branch(instruction inpp, instruction outpp, context *ctxp) { + static constexpr uint32_t lsb = 5u; + static constexpr uint32_t lmask01 = 0xff00001fu; // 0b11111111000000000000000000011111 + static constexpr uint32_t mask0 = 0xff000010u; // 0b11111111000000000000000000010000 + static constexpr uint32_t op_bc = 0x54000000u; // "b.c" ADDR_PCREL19 + static constexpr uint32_t mask1 = 0x7f000000u; // 0b01111111000000000000000000000000 + static constexpr uint32_t op_cbz = 0x34000000u; // "cbz" Rt, ADDR_PCREL19 + static constexpr uint32_t op_cbnz = 0x35000000u; // "cbnz" Rt, ADDR_PCREL19 + static constexpr uint32_t lmask2 = 0xfff8001fu; // 0b11111111111110000000000000011111 + static constexpr uint32_t mask2 = 0x7f000000u; // 0b01111111000000000000000000000000 + static constexpr uint32_t op_tbz = 0x36000000u; // 0b00110110000000000000000000000000 "tbz" Rt, BIT_NUM, ADDR_PCREL14 + static constexpr uint32_t op_tbnz = 0x37000000u; // 0b00110111000000000000000000000000 "tbnz" Rt, BIT_NUM, ADDR_PCREL14 + + const uint32_t ins = *(*inpp); + uint32_t lmask = lmask01; + if ((ins & mask0) != op_bc) { + uint32_t opc = ins & mask1; + if (opc != op_cbz && opc != op_cbnz) { + opc = ins & mask2; + if (opc != op_tbz && opc != op_tbnz) { + return false; + } //if + lmask = lmask2; + } //if + } //if + + intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); + int64_t absolute_addr = reinterpret_cast(*inpp) + ((ins & ~lmask) >> (lsb - 2u)); + int64_t new_pc_offset = + static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // 转移 + bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); + if (!special_fix_type && llabs(new_pc_offset) >= (~lmask >> (lsb + 1))) { + if ((reinterpret_cast(*outpp + 4) & 7u) != 0u) { + (*outpp)[0] = A64_NOP; + ctxp->reset_current_ins(current_idx, ++(*outpp)); + } //if + (*outpp)[0] = (((8u >> 2u) << lsb) & ~lmask) | (ins & lmask); // B.C #0x8 + (*outpp)[1] = 0x14000005u; // B #0x14 + (*outpp)[2] = 0x58000051u; // LDR X17, #0x8 + (*outpp)[3] = 0xd61f0220u; // BR X17 + memcpy(*outpp + 4, &absolute_addr, sizeof(absolute_addr)); + *outpp += 6; + } else { + if (special_fix_type) { + intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); + if (ref_idx <= current_idx) { + new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - + reinterpret_cast(*outpp)) >> 2; + } else { + ctxp->insert_fix_map(ref_idx, *outpp, lsb, ~lmask); + new_pc_offset = 0; + } //if + } //if + + (*outpp)[0] = (static_cast(new_pc_offset << lsb) & ~lmask) | (ins & lmask); + ++(*outpp); + } //if + + ++(*inpp); + return ctxp->process_fix_map(current_idx), true; +} + +//------------------------------------------------------------------------- + +static bool __fix_loadlit(instruction inpp, instruction outpp, context *ctxp) { + const uint32_t ins = *(*inpp); + + // memory prefetch("prfm"), 跳过它 + // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897420050.html + if ((ins & 0xff000000u) == 0xd8000000u) { + ctxp->process_fix_map(ctxp->get_and_set_current_index(*inpp, *outpp)); + ++(*inpp); + return true; + } //if + + static constexpr uint32_t msb = 8u; + static constexpr uint32_t lsb = 5u; + static constexpr uint32_t mask_30 = 0x40000000u; // 0b01000000000000000000000000000000 + static constexpr uint32_t mask_31 = 0x80000000u; // 0b10000000000000000000000000000000 + static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 + static constexpr uint32_t mask_ldr = 0xbf000000u; // 0b10111111000000000000000000000000 + static constexpr uint32_t op_ldr = 0x18000000u; // 0b00011000000000000000000000000000 "LDR Wt/Xt, label" | ADDR_PCREL19 + static constexpr uint32_t mask_ldrv = 0x3f000000u; // 0b00111111000000000000000000000000 + static constexpr uint32_t op_ldrv = 0x1c000000u; // 0b00011100000000000000000000000000 "LDR St/Dt/Qt, label" | ADDR_PCREL19 + static constexpr uint32_t mask_ldrsw = 0xff000000u; // 0b11111111000000000000000000000000 + static constexpr uint32_t op_ldrsw = 0x98000000u; // "LDRSW Xt, label" | ADDR_PCREL19 | load register signed word + // LDR S0, #0 | 0b00011100000000000000000000000000 | 32-bit + // LDR D0, #0 | 0b01011100000000000000000000000000 | 64-bit + // LDR Q0, #0 | 0b10011100000000000000000000000000 | 128-bit + // INVALID | 0b11011100000000000000000000000000 | may be 256-bit + + uint32_t mask = mask_ldr; + uintptr_t faligned = (ins & mask_30) ? 7u : 3u; + if ((ins & mask_ldr) != op_ldr) { + mask = mask_ldrv; + if (faligned != 7u) + faligned = (ins & mask_31) ? 15u : 3u; + if ((ins & mask_ldrv) != op_ldrv) { + if ((ins & mask_ldrsw) != op_ldrsw) { + return false; + } //if + mask = mask_ldrsw; + faligned = 7u; + } //if + } //if + + intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); + int64_t absolute_addr = reinterpret_cast(*inpp) + + ((static_cast(ins << msb) >> (msb + lsb - 2u)) & ~3u); + int64_t new_pc_offset = + static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // 转移 + bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); + // special_fix_type 当存在混合数据和代码时可能会遇到问题 + if (special_fix_type || (llabs(new_pc_offset) + (faligned + 1u - 4u) / 4u) >= + (~lmask >> (lsb + 1))) { // 不准确,但它有效 + while ((reinterpret_cast(*outpp + 2) & faligned) != 0u) { + *(*outpp)++ = A64_NOP; + } + ctxp->reset_current_ins(current_idx, *outpp); + + // 请注意,如果 absolute_addr 处的内存是可写的(非常量),我们将无法获取它。 + // 更糟糕的是,如果special_fix_type是真的,我们可能会意外地覆盖某些东西...... + uint32_t ns = static_cast((faligned + 1) / sizeof(uint32_t)); + (*outpp)[0] = (((8u >> 2u) << lsb) & ~mask) | (ins & lmask); // LDR #0x8 + (*outpp)[1] = 0x14000001u + ns; // B #0xc + memcpy(*outpp + 2, reinterpret_cast(absolute_addr), faligned + 1); + *outpp += 2 + ns; + } else { + faligned >>= 2; // new_pc_offset移位和 4 字节对齐 + while ((new_pc_offset & faligned) != 0) { + *(*outpp)++ = A64_NOP; + new_pc_offset = + static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; + } + ctxp->reset_current_ins(current_idx, *outpp); + + (*outpp)[0] = (static_cast(new_pc_offset << lsb) & ~mask) | (ins & lmask); + ++(*outpp); + } //if + + ++(*inpp); + return ctxp->process_fix_map(current_idx), true; +} + +//------------------------------------------------------------------------- + +static bool __fix_pcreladdr(instruction inpp, instruction outpp, context *ctxp) { + // 将 PC 相对地址加载到寄存器中 + // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897645644.html + static constexpr uint32_t msb = 8u; + static constexpr uint32_t lsb = 5u; + static constexpr uint32_t mask = 0x9f000000u; // 0b10011111000000000000000000000000 + static constexpr uint32_t rmask = 0x0000001fu; // 0b00000000000000000000000000011111 + static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 + static constexpr uint32_t fmask = 0x00ffffffu; // 0b00000000111111111111111111111111 + static constexpr uint32_t max_val = 0x001fffffu; // 0b00000000000111111111111111111111 + static constexpr uint32_t op_adr = 0x10000000u; // "adr" Rd, ADDR_PCREL21 + static constexpr uint32_t op_adrp = 0x90000000u; // "adrp" Rd, ADDR_ADRP + + const uint32_t ins = *(*inpp); + intptr_t current_idx; + switch (ins & mask) { + case op_adr: { + current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); + int64_t lsb_bytes = static_cast(ins << 1u) >> 30u; + int64_t absolute_addr = reinterpret_cast(*inpp) + + (((static_cast(ins << msb) >> (msb + lsb - 2u)) & + ~3u) | lsb_bytes); + int64_t new_pc_offset = static_cast(absolute_addr - + reinterpret_cast(*outpp)); + bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); + if (!special_fix_type && llabs(new_pc_offset) >= (max_val >> 1)) { + if ((reinterpret_cast(*outpp + 2) & 7u) != 0u) { + (*outpp)[0] = A64_NOP; + ctxp->reset_current_ins(current_idx, ++(*outpp)); + } //if + + (*outpp)[0] = + 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8 + (*outpp)[1] = 0x14000003u; // B #0xc + memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); + *outpp += 4; + } else { + if (special_fix_type) { + intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr & ~3ull); + if (ref_idx <= current_idx) { + new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - + reinterpret_cast(*outpp)); + } else { + ctxp->insert_fix_map(ref_idx, *outpp, lsb, fmask); + new_pc_offset = 0; + } //if + } //if + + // lsb_bytes永远不会改变,所以我们可以使用 lmask 来保留它 + (*outpp)[0] = (static_cast(new_pc_offset << (lsb - 2u)) & fmask) | + (ins & lmask); + ++(*outpp); + } //if + } + break; + case op_adrp: { + current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); + int32_t lsb_bytes = static_cast(ins << 1u) >> 30u; + int64_t absolute_addr = (reinterpret_cast(*inpp) & ~0xfffll) + + ((((static_cast(ins << msb) >> (msb + lsb - 2u)) & + ~3u) | lsb_bytes) << 12); + A64_LOGI("ins = 0x%.8X, pc = %p, abs_addr = %p", + ins, *inpp, reinterpret_cast(absolute_addr)); + if (ctxp->is_in_fixing_range(absolute_addr)) { + intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr/* & ~3ull*/); + if (ref_idx > current_idx) { + // absolute_addr的底部 12 位被屏蔽, + // 所以ref_idx必须小于或等于current_idx! + A64_LOGE("ref_idx must be less than or equal to current_idx!"); + } //if + + // *absolute_addr可能会因搬迁修复而更改 + A64_LOGI("What is the correct way to fix this?"); + *(*outpp)++ = ins; // 0x90000000u; + } else { + if ((reinterpret_cast(*outpp + 2) & 7u) != 0u) { + (*outpp)[0] = A64_NOP; + ctxp->reset_current_ins(current_idx, ++(*outpp)); + } //if + + (*outpp)[0] = + 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8 + (*outpp)[1] = 0x14000003u; // B #0xc + memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); // potential overflow? (潜在的溢出?) + *outpp += 4; + } //if + } + break; + default: + return false; + } + + ctxp->process_fix_map(current_idx); + ++(*inpp); + return true; +} + +//------------------------------------------------------------------------- +#define __flush_cache(c, n) __builtin___clear_cache(reinterpret_cast(c), reinterpret_cast(c) + n) + +static void __fix_instructions(uint32_t *__restrict inp, int32_t count, uint32_t *__restrict outp) { + context ctx; + ctx.basep = reinterpret_cast(inp); + ctx.endp = reinterpret_cast(inp + count); + memset(ctx.dat, 0, sizeof(ctx.dat)); + static_assert(sizeof(ctx.dat) / sizeof(ctx.dat[0]) == A64_MAX_INSTRUCTIONS, + "please use A64_MAX_INSTRUCTIONS!"); +#ifndef NDEBUG + if (count > A64_MAX_INSTRUCTIONS) { + A64_LOGE("too many fixing instructions!"); + } //if +#endif // NDEBUG + + uint32_t *const outp_base = outp; + + while (--count >= 0) { + if (__fix_branch_imm(&inp, &outp, &ctx)) continue; + if (__fix_cond_comp_test_branch(&inp, &outp, &ctx)) continue; + if (__fix_loadlit(&inp, &outp, &ctx)) continue; + if (__fix_pcreladdr(&inp, &outp, &ctx)) continue; + + // 无 PC 相对偏移 + ctx.process_fix_map(ctx.get_and_set_current_index(inp, outp)); + *(outp++) = *(inp++); + } + + static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111 + auto callback = reinterpret_cast(inp); + auto pc_offset = static_cast(callback - reinterpret_cast(outp)) >> 2; + if (llabs(pc_offset) >= (mask >> 1)) { + if ((reinterpret_cast(outp + 2) & 7u) != 0u) { + outp[0] = A64_NOP; + ++outp; + } //if + outp[0] = 0x58000051u; // LDR X17, #0x8 + outp[1] = 0xd61f0220u; // BR X17 + *reinterpret_cast(outp + 2) = callback; + outp += 4; + } else { + outp[0] = 0x14000000u | (pc_offset & mask); // "B" ADDR_PCREL26 + ++outp; + } //if + + const uintptr_t total = (outp - outp_base) * sizeof(uint32_t); + __flush_cache(outp_base, total); // necessary (必要) +} + +//------------------------------------------------------------------------- + +extern "C" { +#define __attribute __attribute__ +#define aligned(x) __aligned__(x) +#define __intval(p) reinterpret_cast(p) +#define __uintval(p) reinterpret_cast(p) +#define __ptr(p) reinterpret_cast(p) +#define __page_size 4096 +#define __page_align(n) __align_up(static_cast(n), __page_size) +#define __ptr_align(x) __ptr(__align_down(reinterpret_cast(x), __page_size)) +#define __align_up(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) +#define __align_down(x, n) ((x) & -(n)) +#define __countof(x) static_cast(sizeof(x) / sizeof((x)[0])) // 必须签名 +#define __atomic_increase(p) __sync_add_and_fetch(p, 1) +#define __sync_cmpswap(p, v, n) __sync_bool_compare_and_swap(p, v, n) +#define __predict_true(exp) __builtin_expect((exp) != 0, 1) +#define __make_rwx(p, n) ::mprotect(__ptr_align(p), \ + __page_align(__uintval(p) + n) != __page_align(__uintval(p)) ? __page_align(n) + __page_size : __page_align(n), \ + PROT_READ | PROT_WRITE | PROT_EXEC) + +//------------------------------------------------------------------------- + +static __attribute((aligned(__page_size))) uint32_t __insns_pool[A64_MAX_BACKUPS][ + A64_MAX_INSTRUCTIONS * 10]; + +//------------------------------------------------------------------------- + +class A64HookInit { +public: + A64HookInit() { + __make_rwx(__insns_pool, sizeof(__insns_pool)); + A64_LOGI("insns pool initialized."); + } +}; +static A64HookInit __init; + +//------------------------------------------------------------------------- + +static uint32_t *FastAllocateTrampoline() { + static_assert((A64_MAX_INSTRUCTIONS * 10 * sizeof(uint32_t)) % 8 == 0, "8-byte align"); + static volatile int32_t __index = -1; + + int32_t i = __atomic_increase(&__index); + if (__predict_true(i >= 0 && i < __countof(__insns_pool))) { + return __insns_pool[i]; + } //if + + A64_LOGE("failed to allocate trampoline!"); + return NULL; +} + +//------------------------------------------------------------------------- + +A64_JNIEXPORT void *A64HookFunctionV(void *const symbol, void *const replace, + void *const rwx, const uintptr_t rwx_size) { + static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111 + + uint32_t *trampoline = static_cast(rwx), *original = static_cast(symbol); + + static_assert(A64_MAX_INSTRUCTIONS >= 5, "please fix A64_MAX_INSTRUCTIONS!"); + auto pc_offset = static_cast(__intval(replace) - __intval(symbol)) >> 2; + if (llabs(pc_offset) >= (mask >> 1)) { + int32_t count = (reinterpret_cast(original + 2) & 7u) != 0u ? 5 : 4; + if (trampoline) { + if (rwx_size < count * 10u) { + A64_LOGI("rwx size is too small to hold %u bytes backup instructions!", + count * 10u); + return NULL; + } //if + __fix_instructions(original, count, trampoline); + } //if + + if (__make_rwx(original, 5 * sizeof(uint32_t)) == 0) { + if (count == 5) { + original[0] = A64_NOP; + ++original; + } //if + original[0] = 0x58000051u; // LDR X17, #0x8 + original[1] = 0xd61f0220u; // BR X17 + *reinterpret_cast(original + 2) = __intval(replace); + __flush_cache(symbol, 5 * sizeof(uint32_t)); + + A64_LOGI("inline hook %p->%p successfully! %zu bytes overwritten", + symbol, replace, 5 * sizeof(uint32_t)); + } else { + A64_LOGE("mprotect failed with errno = %d, p = %p, size = %zu", + errno, original, 5 * sizeof(uint32_t)); + trampoline = NULL; + } //if + } else { + if (trampoline) { + if (rwx_size < 1u * 10u) { + A64_LOGI("rwx size is too small to hold %u bytes backup instructions!", 1u * 10u); + return NULL; + } //if + __fix_instructions(original, 1, trampoline); + } //if + + if (__make_rwx(original, 1 * sizeof(uint32_t)) == 0) { + __sync_cmpswap(original, *original, + 0x14000000u | (pc_offset & mask)); // "B" ADDR_PCREL26 + __flush_cache(symbol, 1 * sizeof(uint32_t)); + + A64_LOGI("inline hook %p->%p successfully! %zu bytes overwritten", + symbol, replace, 1 * sizeof(uint32_t)); + } else { + A64_LOGE("mprotect failed with errno = %d, p = %p, size = %zu", + errno, original, 1 * sizeof(uint32_t)); + trampoline = NULL; + } //if + } //if + + return trampoline; +} + +//------------------------------------------------------------------------- + +A64_JNIEXPORT void A64HookFunction(void *const symbol, void *const replace, void **result) { + void *trampoline = NULL; + if (result != NULL) { + trampoline = FastAllocateTrampoline(); + *result = trampoline; + if (trampoline == NULL) return; + } //if + + //修复安卓10.text段默认为只读 + __make_rwx(symbol, 5 * sizeof(size_t)); + + trampoline = A64HookFunctionV(symbol, replace, trampoline, A64_MAX_INSTRUCTIONS * 10u); + if (trampoline == NULL && result != NULL) { + *result = NULL; + } //if +} +} + +#endif // defined(__aarch64__) \ No newline at end of file diff --git a/app/src/main/jni/And64InlineHook/And64InlineHook.hpp b/app/src/main/jni/And64InlineHook/And64InlineHook.hpp new file mode 100644 index 0000000..9b95236 --- /dev/null +++ b/app/src/main/jni/And64InlineHook/And64InlineHook.hpp @@ -0,0 +1,43 @@ +/* + * @date : 2018/04/18 + * @author : Rprop (r_prop@outlook.com) + * https://github.com/Rprop/And64InlineHook + */ +/* +//2023/6/26 by艾琳汉化(团队:无尽的四月) 游戏MOD交流群368969530 + + 麻省理工学院执照 + + 版权所有 (c) 2018 Rprop (r_prop@outlook.com) + + 特此免费授予任何获得副本的人 + 本软件和相关文档文件(“软件”),以处理 + 在软件中不受限制,包括但不限于权利 + 使用、复制、修改、合并、发布、分发、再许可和/或出售 + 软件的副本,并允许软件所针对的人员 + 提供,但须符合以下条件: + + 上述版权声明和本许可声明应包含在所有 + 本软件的副本或大部分内容。 + + 本软件按“原样”提供,不提供任何形式的明示或保证 + 暗示,包括但不限于适销性保证, + 适用于特定目的且不侵权。在任何情况下,都不得 + 作者或版权所有者对任何索赔、损害赔偿或其他索赔、损害赔偿或其他责任 + 责任,无论是在合同、侵权或其他诉讼中,由以下原因引起: + 出于或与本软件有关,或在 + 软件。 + */ +#pragma once +#define A64_MAX_BACKUPS 256 + +#ifdef __cplusplus +extern "C" { +#endif + +void A64HookFunction(void *const symbol, void *const replace, void **result); +void *A64HookFunctionV(void *const symbol, void *const replace, void *const rwx, const uintptr_t rwx_size); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/app/src/main/jni/And64InlineHook/LICENSE b/app/src/main/jni/And64InlineHook/LICENSE new file mode 100644 index 0000000..75a6020 --- /dev/null +++ b/app/src/main/jni/And64InlineHook/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 RLib + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/app/src/main/jni/And64InlineHook/README.md b/app/src/main/jni/And64InlineHook/README.md new file mode 100644 index 0000000..44f651d --- /dev/null +++ b/app/src/main/jni/And64InlineHook/README.md @@ -0,0 +1,7 @@ +# And64InlineHook +Lightweight ARMv8-A(ARM64, AArch64, Little-Endian) Inline Hook Library for Android C/C++ + +# References +[Arm Compiler armasm User Guide](http://infocenter.arm.com/help/topic/com.arm.doc.100069_0610_00_en/pge1427898258836.html) +[Procedure Call Standard for the Arm® 64-bit Architecture (AArch64)](https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst) + diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk new file mode 100644 index 0000000..1379227 --- /dev/null +++ b/app/src/main/jni/Android.mk @@ -0,0 +1,31 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := Algui + +LOCAL_CFLAGS := -w -s -Wno-error=format-security -fvisibility=hidden -fpermissive -fexceptions +ifeq ($(TARGET_ARCH_ABI),x86)#对于x86 + LOCAL_CFLAGS += -ffast-math -mtune=atom -mssse3 -mfpmath=sse +endif +LOCAL_CPPFLAGS := -w -s -Wno-error=format-security -fvisibility=hidden -Werror -std=c++17 +LOCAL_CPPFLAGS += -Wno-error=c++11-narrowing -fpermissive -Wall -fexceptions +LOCAL_LDFLAGS += -Wl,--gc-sections,--strip-all,-llog +LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2 +LOCAL_ARM_MODE := arm + +LOCAL_CPP_EXTENSION := .cpp .cc + +LOCAL_SRC_FILES := main.cpp\ + Substrate/hde64.c \ + Substrate/SubstrateDebug.cpp \ + Substrate/SubstrateHook.cpp \ + Substrate/SubstratePosixMemory.cpp \ + Substrate/SymbolFinder.cpp \ + And64InlineHook/And64InlineHook.cpp \ + ByNameModding/Tools.cpp \ + ByNameModding/fake_dlfcn.cpp \ + ByNameModding/Il2Cpp.cpp \ + +include $(BUILD_SHARED_LIBRARY) + diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk new file mode 100644 index 0000000..250e25c --- /dev/null +++ b/app/src/main/jni/Application.mk @@ -0,0 +1,5 @@ +APP_STL := c++_static +APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 +APP_OPTIM := release +APP_THIN_ARCHIVE := true#瘦归档 +APP_PIE := true diff --git a/app/src/main/jni/ByNameModding/Il2Cpp.cpp b/app/src/main/jni/ByNameModding/Il2Cpp.cpp new file mode 100644 index 0000000..7d03b6b --- /dev/null +++ b/app/src/main/jni/ByNameModding/Il2Cpp.cpp @@ -0,0 +1,368 @@ +#include "Il2Cpp.h" + +#include "Includes.h" +#include "fake_dlfcn.h" + +#define LOG_TAG "Games-Il2Cpp" + +#define IL2CPP_LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define IL2CPP_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) +#define IL2CPP_LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) +#define IL2CPP_LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +// =========================================================================== // +namespace { + const void *(*il2cpp_assembly_get_image)(const void *assembly); + void *(*il2cpp_domain_get)(); + void **(*il2cpp_domain_get_assemblies)(const void *domain, size_t *size); + const char *(*il2cpp_image_get_name)(void *image); + void *(*il2cpp_class_from_name)(const void *image, const char *namespaze, const char *name); + void *(*il2cpp_class_get_field_from_name)(void *klass, const char *name); + void *(*il2cpp_class_get_method_from_name)(void *klass, const char *name, int argsCount); + size_t (*il2cpp_field_get_offset)(void *field); + void (*il2cpp_field_static_get_value)(void *field, void *value); + void (*il2cpp_field_static_set_value)(void *field, void *value); + void *(*il2cpp_array_new)(void *elementTypeInfo, size_t length); + uint16_t *(*il2cpp_string_chars)(void *str); + Il2CppString *(*il2cpp_string_new)(const char *str); + Il2CppString *(*il2cpp_string_new_utf16)(const wchar_t *str, int32_t length); + char *(*il2cpp_type_get_name)(void *type); + void* (*il2cpp_method_get_param)(void *method, uint32_t index); + void* (*il2cpp_class_get_methods)(void *klass, void* *iter); + const char* (*il2cpp_method_get_name)(void *method); + void *(*il2cpp_object_new)(void *klass); +} +// =========================================================================== // +void Il2CppAttach(const char *name) { + void *handle = dlopen_ex(name, 0); + while (!handle) { + handle = dlopen_ex(name, 0); + sleep(1); + } + + il2cpp_assembly_get_image = (const void *(*)(const void *)) dlsym_ex(handle, "il2cpp_assembly_get_image"); + il2cpp_domain_get = (void *(*)()) dlsym_ex(handle, "il2cpp_domain_get"); + il2cpp_domain_get_assemblies = (void **(*)(const void* , size_t*)) dlsym_ex(handle, "il2cpp_domain_get_assemblies"); + il2cpp_image_get_name = (const char *(*)(void *)) dlsym_ex(handle, "il2cpp_image_get_name"); + il2cpp_class_from_name = (void* (*)(const void*, const char*, const char *)) dlsym_ex(handle, "il2cpp_class_from_name"); + il2cpp_class_get_field_from_name = (void* (*)(void*, const char *)) dlsym_ex(handle, "il2cpp_class_get_field_from_name"); + il2cpp_class_get_method_from_name = (void* (*)(void *, const char*, int)) dlsym_ex(handle, "il2cpp_class_get_method_from_name"); + il2cpp_field_get_offset = (size_t (*)(void *)) dlsym_ex(handle, "il2cpp_field_get_offset"); + il2cpp_field_static_get_value = (void (*)(void*, void *)) dlsym_ex(handle, "il2cpp_field_static_get_value"); + il2cpp_field_static_set_value = (void (*)(void*, void *)) dlsym_ex(handle, "il2cpp_field_static_set_value"); + il2cpp_array_new = (void *(*)(void*, size_t)) dlsym_ex(handle, "il2cpp_array_new"); + il2cpp_string_chars = (uint16_t *(*)(void*)) dlsym_ex(handle, "il2cpp_string_chars"); + il2cpp_string_new = (Il2CppString *(*)(const char *)) dlsym_ex(handle, "il2cpp_string_new"); + il2cpp_string_new_utf16 = (Il2CppString *(*)(const wchar_t *, int32_t)) dlsym_ex(handle, "il2cpp_string_new"); + il2cpp_type_get_name = (char *(*)(void *)) dlsym_ex(handle, "il2cpp_type_get_name"); + il2cpp_method_get_param = (void *(*)(void *, uint32_t)) dlsym_ex(handle, "il2cpp_method_get_param"); + il2cpp_class_get_methods = (void *(*)(void *, void **)) dlsym_ex(handle, "il2cpp_class_get_methods"); + il2cpp_method_get_name = (const char *(*)(void *)) dlsym_ex(handle, "il2cpp_method_get_name"); + il2cpp_object_new = (void *(*)(void *)) dlsym_ex(handle, "il2cpp_object_new"); + + dlclose_ex(handle); +} +// =========================================================================== // +typedef unsigned short UTF16; +typedef wchar_t UTF32; +typedef char UTF8; + +int is_surrogate(UTF16 uc) { + return (uc - 0xd800u) < 2048u; +} + +int is_high_surrogate(UTF16 uc) { + return (uc & 0xfffffc00) == 0xd800; +} + +int is_low_surrogate(UTF16 uc) { + return (uc & 0xfffffc00) == 0xdc00; +} + +UTF32 surrogate_to_utf32(UTF16 high, UTF16 low) { + return (high << 10) + low - 0x35fdc00; +} + +const char* utf16_to_utf8(const UTF16* source, size_t len) { + std::u16string s(source, source + len); + std::wstring_convert, char16_t> convert; + return convert.to_bytes(s).c_str(); +} + +const wchar_t* utf16_to_utf32(const UTF16* source, size_t len) { + auto output = new UTF32[len + 1]; + + for (int i = 0; i < len; i++) { + const UTF16 uc = source[i]; + if (!is_surrogate(uc)) { + output[i] = uc; + } + else { + if (is_high_surrogate(uc) && is_low_surrogate(source[i])) + output[i] = surrogate_to_utf32(uc, source[i]); + else + output[i] = L'?'; + } + } + + output[len] = L'\0'; + return output; +} +// =========================================================================== // +const char* Il2CppString::CString() { + return utf16_to_utf8(&this->start_char, this->length); +} + +const wchar_t* Il2CppString::WCString() { + return utf16_to_utf32(&this->start_char, this->length); +} + +Il2CppString *Il2CppString::CreateMonoString(const char *s) { + return il2cpp_string_new(s); +} + +Il2CppString *Il2CppString::CreateMonoString(const wchar_t *s, int len) { + return il2cpp_string_new_utf16(s, len); +} +// =========================================================================== // +void *Il2CppGetImageByName(const char *image) { + size_t size; + void **assemblies = il2cpp_domain_get_assemblies(il2cpp_domain_get(), &size); + for(int i = 0; i < size; ++i) { + void *img = (void *)il2cpp_assembly_get_image(assemblies[i]); + + const char *img_name = il2cpp_image_get_name(img); + + if(strcmp(img_name, image) == 0) { + return img; + } + } + return 0; +} +// ================================================================================================================ // +void *Il2CppGetClassType(const char *image, const char *namespaze, const char *clazz) { + static std::map cache; + + std::string s = image; + s += namespaze; + s += clazz; + + if (cache.count(s) > 0) + return cache[s]; + + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return 0; + } + + void *klass = il2cpp_class_from_name(img, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s!", clazz); + return 0; + } + + cache[s] = klass; + return klass; +} +// ================================================================================================================ // +void *Il2CppCreateClassInstance(const char *image, const char *namespaze, const char *clazz) { + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return 0; + } + + void *klass = Il2CppGetClassType(image, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s!", clazz); + return 0; + } + + void *obj = il2cpp_object_new(klass); + if(!obj) + { + IL2CPP_LOGE("Can't create object for %s", clazz); + return 0; + } + + return obj; +} +// ================================================================================================================ // +void* Il2CppCreateArray(const char *image, const char *namespaze, const char *clazz, size_t length) { + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return 0; + } + void *klass = Il2CppGetClassType(image, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s!", clazz); + return 0; + } + + return il2cpp_array_new(klass, length); +} +// ================================================================================================================ // +void Il2CppGetStaticFieldValue(const char *image, const char *namespaze, const char *clazz, const char *name, void *output) { + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return; + } + void *klass = Il2CppGetClassType(image, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s for field %s!", clazz, name); + return; + } + + void *field = il2cpp_class_get_field_from_name(klass, name); + if(!field) { + IL2CPP_LOGE("Can't find field %s in class %s!", name, clazz); + return; + } + + il2cpp_field_static_get_value(field, output); +} +// ================================================================================================================ // +void Il2CppSetStaticFieldValue(const char *image, const char *namespaze, const char *clazz, const char *name, void* value) { + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return; + } + void *klass = Il2CppGetClassType(image, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s for field %s!", clazz, name); + return; + } + + void *field = il2cpp_class_get_field_from_name(klass, name); + if(!field) { + IL2CPP_LOGE("Can't find field %s in class %s!", name, clazz); + return; + } + + il2cpp_field_static_set_value(field, value); +} +// ================================================================================================================ // +void *Il2CppGetMethodOffset(const char *image, const char *namespaze, const char *clazz, const char *name, int argsCount) { + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return 0; + } + + void *klass = Il2CppGetClassType(image, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s for method %s!", clazz, name); + return 0; + } + + void **method = (void**)il2cpp_class_get_method_from_name(klass, name, argsCount); + if(!method) { + IL2CPP_LOGE("Can't find method %s in class %s!", name, clazz); + return 0; + } + IL2CPP_LOGD("%s - [%s] %s::%s: %p", image, namespaze, clazz, name, *method); + return *method; +} +// ================================================================================================================ // +void *Il2CppGetMethodOffset(const char *image, const char *namespaze, const char *clazz, const char *name, char** args, int argsCount) { + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return 0; + } + + void *klass = Il2CppGetClassType(image, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s for method %s!", clazz, name); + return 0; + } + + void *iter = 0; + + int score = 0; + + void **method = (void**) il2cpp_class_get_methods(klass, &iter); + while(method) { + const char *fname = il2cpp_method_get_name(method); + if(strcmp(fname, name) == 0) { + for (int i = 0; i < argsCount; i++) { + void *arg = il2cpp_method_get_param(method, i); + if (arg) { + const char *tname = il2cpp_type_get_name(arg); + if (strcmp(tname, args[i]) == 0) { + score++; + } else { + IL2CPP_LOGI("Argument at index %d didn't matched requested argument!\n\tRequested: %s\n\tActual: %s\nnSkipping function...", i, args[i], tname); + score = 0; + goto skip; + } + } + } + } + skip: + + if(score == argsCount) { + IL2CPP_LOGD("%s - [%s] %s::%s: %p", image, namespaze, clazz, name, *method); + return *method; + } + + method = (void **) il2cpp_class_get_methods(klass, &iter); + } + IL2CPP_LOGE("Cannot find function %s in class %s!", name, clazz); + return 0; +} +// ================================================================================================================ // +size_t Il2CppGetFieldOffset(const char *image, const char *namespaze, const char *clazz, const char *name) { + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return -1; + } + void *klass = Il2CppGetClassType(image, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s for field %s!", clazz, name); + return -1; + } + + void *field = il2cpp_class_get_field_from_name(klass, name); + if(!field) { + IL2CPP_LOGE("Can't find field %s in class %s!", name, clazz); + return -1; + } + auto result = il2cpp_field_get_offset(field); + IL2CPP_LOGD("%s - [%s] %s::%s: %p", image, namespaze, clazz, name, (void *) result); + return result; +} + +unsigned long Il2CppGetStaticFieldOffset(const char *image, const char *namespaze, const char *clazz, const char *name) { + void *img = Il2CppGetImageByName(image); + if(!img) { + IL2CPP_LOGE("Can't find image %s!", image); + return -1; + } + void *klass = Il2CppGetClassType(image, namespaze, clazz); + if(!klass) { + IL2CPP_LOGE("Can't find class %s for field %s!", clazz, name); + return -1; + } + + FieldInfo *field = (FieldInfo*)il2cpp_class_get_field_from_name(klass, name); + if(!field) { + IL2CPP_LOGE("Can't find field %s in class %s!", name, clazz); + return -1; + } + return (unsigned long)((uint64_t)field->parent->static_fields + field->offset); +} + +// ================================================================================================================ // +bool Il2CppIsAssembliesLoaded() { + size_t size; + void **assemblies = il2cpp_domain_get_assemblies(il2cpp_domain_get(), &size); + + return size != 0 && assemblies != 0; +} +// ================================================================================================================ // + diff --git a/app/src/main/jni/ByNameModding/Il2Cpp.h b/app/src/main/jni/ByNameModding/Il2Cpp.h new file mode 100644 index 0000000..0890d2a --- /dev/null +++ b/app/src/main/jni/ByNameModding/Il2Cpp.h @@ -0,0 +1,284 @@ +// +// Created by aimar on 12/28/2019. +// Modified by baydroid on 13/13/1945 +// + +#pragma once + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#ifndef IL2CPP_H +#define IL2CPP_H + +// ================================================================================================================================ // +typedef void(*Il2CppMethodPointer)(); + +struct MethodInfo; + +struct VirtualInvokeData { + Il2CppMethodPointer methodPtr; + const MethodInfo* method; +}; + +struct Il2CppType { + void* data; + unsigned int bits; +}; + +struct Il2CppClass; + +struct Il2CppObject { + Il2CppClass *klass; + void *monitor; +}; + +union Il2CppRGCTXData { + void* rgctxDataDummy; + const MethodInfo* method; + const Il2CppType* type; + Il2CppClass* klass; +}; + +struct Il2CppClass_1 { + void* image; + void* gc_desc; + const char* name; + const char* namespaze; + Il2CppType* byval_arg; + Il2CppType* this_arg; + Il2CppClass* element_class; + Il2CppClass* castClass; + Il2CppClass* declaringType; + Il2CppClass* parent; + void *generic_class; + void* typeDefinition; + void* interopData; + void* fields; + void* events; + void* properties; + void* methods; + Il2CppClass** nestedTypes; + Il2CppClass** implementedInterfaces; + void* interfaceOffsets; +}; + +struct Il2CppClass_2 { + Il2CppClass** typeHierarchy; + uint32_t cctor_started; + uint32_t cctor_finished; + uint64_t cctor_thread; + int32_t genericContainerIndex; + int32_t customAttributeIndex; + uint32_t instance_size; + uint32_t actualSize; + uint32_t element_size; + int32_t native_size; + uint32_t static_fields_size; + uint32_t thread_static_fields_size; + int32_t thread_static_fields_offset; + uint32_t flags; + uint32_t token; + uint16_t method_count; + uint16_t property_count; + uint16_t field_count; + uint16_t event_count; + uint16_t nested_type_count; + uint16_t vtable_count; + uint16_t interfaces_count; + uint16_t interface_offsets_count; + uint8_t typeHierarchyDepth; + uint8_t genericRecursionDepth; + uint8_t rank; + uint8_t minimumAlignment; + uint8_t packingSize; + uint8_t bitflags1; + uint8_t bitflags2; +}; + +struct Il2CppClass { + Il2CppClass_1 _1; + void* static_fields; + Il2CppRGCTXData* rgctx_data; + Il2CppClass_2 _2; + VirtualInvokeData vtable[255]; +}; + +typedef int32_t il2cpp_array_size_t; +typedef int32_t il2cpp_array_lower_bound_t; +struct Il2CppArrayBounds { + il2cpp_array_size_t length; + il2cpp_array_lower_bound_t lower_bound; +}; + +struct MethodInfo { + Il2CppMethodPointer methodPointer; + void* invoker_method; + const char* name; + Il2CppClass *declaring_type; + const Il2CppType *return_type; + const void* parameters; + union { + const Il2CppRGCTXData* rgctx_data; + const void* methodDefinition; + }; + union { + const void* genericMethod; + const void* genericContainer; + }; + int32_t customAttributeIndex; + uint32_t token; + uint16_t flags; + uint16_t iflags; + uint16_t slot; + uint8_t parameters_count; + uint8_t bitflags; +}; + +struct FieldInfo { +public: + const char* name; + const Il2CppType* type; + Il2CppClass *parent; + int32_t offset; + uint32_t token; +}; + +template struct Il2CppArray { + Il2CppClass *klass; + void *monitor; + void *bounds; + int max_length; + T m_Items[65535]; + + int getLength() { + return max_length; + } + + T *getPointer() { + return (T *)m_Items; + } + + T &operator[](int i) { + return m_Items[i]; + } + + T &operator[](int i) const { + return m_Items[i]; + } +}; + +template +using MonoArray = Il2CppArray; + +struct Il2CppString { + Il2CppClass *klass; + void *monitor; + int32_t length; + uint16_t start_char; + + const char *CString(); + + const wchar_t *WCString(); + + static Il2CppString *CreateMonoString(const char *s); + static Il2CppString *CreateMonoString(const wchar_t *s, int len); + + int getLength() { + return length; + } +}; + +typedef Il2CppString MonoString; + +template struct Il2CppList { + Il2CppClass *klass; + void *unk1; + Il2CppArray *items; + int size; + int version; + + T *getItems() { + return items->getPointer(); + } + + int getSize() { + return size; + } + + int getVersion() { + return version; + } + + T &operator[](int i) { + return items->m_Items[i]; + } + + T &operator[](int i) const { + return items->m_Items[i]; + } +}; + +template +using MonoList = Il2CppList; + +template struct Il2CppDictionary { + Il2CppClass *klass; + void *unk1; + Il2CppArray *table; + Il2CppArray *linkSlots; + Il2CppArray *keys; + Il2CppArray *values; + int touchedSlots; + int emptySlot; + int size; + + K *getKeys() { + return keys->getPointer(); + } + + V *getValues() { + return values->getPointer(); + } + + int getNumKeys() { + return keys->getLength(); + } + + int getNumValues() { + return values->getLength(); + } + + int getSize() { + return size; + } +}; + +template +using Dictionary = Il2CppDictionary; + +void Il2CppAttach(const char *name = "libil2cpp.so"); +void *Il2CppGetImageByName(const char *image); +void *Il2CppGetClassType(const char *image, const char *namespaze, const char *clazz); +void *Il2CppCreateClassInstance(const char *image, const char *namespaze, const char *clazz); +void* Il2CppCreateArray(const char *image, const char *namespaze, const char *clazz, size_t length); + +void Il2CppGetStaticFieldValue(const char *image, const char *namespaze, const char *clazz, const char *name, void *output); +void Il2CppSetStaticFieldValue(const char *image, const char *namespaze, const char *clazz, const char *name, void* value); + +void *Il2CppGetMethodOffset(const char *image, const char *namespaze, const char *clazz, const char *name, int argsCount = 0); +void *Il2CppGetMethodOffset(const char *image, const char *namespaze, const char *clazz, const char *name, char** args, int argsCount); + +size_t Il2CppGetFieldOffset(const char *image, const char *namespaze, const char *clazz, const char *name); + +unsigned long Il2CppGetStaticFieldOffset(const char *image, const char *namespaze, const char *clazz, const char *name); + +bool Il2CppIsAssembliesLoaded(); +#endif + diff --git a/app/src/main/jni/ByNameModding/Includes.h b/app/src/main/jni/ByNameModding/Includes.h new file mode 100644 index 0000000..38852ee --- /dev/null +++ b/app/src/main/jni/ByNameModding/Includes.h @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#define IS_DEBUG + +#if defined(IS_DEBUG) +#define LOG_TAG "Games_LOG" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +#else +#define LOGI(...) +#define LOGD(...) +#define LOGW(...) +#define LOGE(...) +#endif diff --git a/app/src/main/jni/ByNameModding/Tools.cpp b/app/src/main/jni/ByNameModding/Tools.cpp new file mode 100644 index 0000000..b01950a --- /dev/null +++ b/app/src/main/jni/ByNameModding/Tools.cpp @@ -0,0 +1,197 @@ +#include "Tools.h" + +#if defined(__arm__) +#define process_vm_readv_syscall 376 +#define process_vm_writev_syscall 377 +#elif defined(__aarch64__) +#define process_vm_readv_syscall 270 +#define process_vm_writev_syscall 271 +#elif defined(__i386__) +#define process_vm_readv_syscall 347 +#define process_vm_writev_syscall 348 +#else +#define process_vm_readv_syscall 310 +#define process_vm_writev_syscall 311 +#endif + +pid_t target_pid = -1; + +ssize_t process_v(pid_t __pid, const struct iovec *__local_iov, unsigned long __local_iov_count, const struct iovec *__remote_iov, unsigned long __remote_iov_count, unsigned long __flags, bool iswrite) { + return syscall((iswrite ? process_vm_writev_syscall : process_vm_readv_syscall), __pid, __local_iov, __local_iov_count, __remote_iov, __remote_iov_count, __flags); +} + +bool pvm(void *address, void *buffer, size_t size, bool write = false) { + struct iovec local[1]; + struct iovec remote[1]; + + local[0].iov_base = buffer; + local[0].iov_len = size; + remote[0].iov_base = address; + remote[0].iov_len = size; + + if (target_pid == -1) { + target_pid = getpid(); + } + + ssize_t bytes = process_v(target_pid, local, 1, remote, 1, 0, write); + return bytes == size; +} + +void Tools::Hook(void *target, void *replace, void **backup) { + unsigned long page_size = sysconf(_SC_PAGESIZE); + unsigned long size = page_size * sizeof(uintptr_t); + void *p = (void *) ((uintptr_t) target - ((uintptr_t) target % page_size) - page_size); + if (mprotect(p, (size_t) size, PROT_EXEC | PROT_READ | PROT_WRITE) == 0) { + MSHookFunction(target, replace, backup); + } +} + +bool Tools::Read(void *addr, void *buffer, size_t length) { + return memcpy(buffer, addr, length) != 0; +} + +bool Tools::Write(void *addr, void *buffer, size_t length) { + return memcpy(addr, buffer, length) != 0; +} + +bool Tools::ReadAddr(void *addr, void *buffer, size_t length) { + unsigned long page_size = sysconf(_SC_PAGESIZE); + unsigned long size = page_size * sizeof(uintptr_t); + return mprotect((void *) ((uintptr_t) addr - ((uintptr_t) addr % page_size) - page_size), (size_t) size, PROT_EXEC | PROT_READ | PROT_WRITE) == 0 && memcpy(buffer, addr, length) != 0; +} + +bool Tools::WriteAddr(void *addr, void *buffer, size_t length) { + unsigned long page_size = sysconf(_SC_PAGESIZE); + unsigned long size = page_size * sizeof(uintptr_t); + return mprotect((void *) ((uintptr_t) addr - ((uintptr_t) addr % page_size) - page_size), (size_t) size, PROT_EXEC | PROT_READ | PROT_WRITE) == 0 && memcpy(addr, buffer, length) != 0; +} + +bool Tools::PVM_ReadAddr(void *addr, void *buffer, size_t length) { + return pvm(addr, buffer, length, false); +} + +bool Tools::PVM_WriteAddr(void *addr, void *buffer, size_t length) { + return pvm(addr, buffer, length, true); +} + +bool Tools::IsPtrValid(void *addr) { + static int fd = -1; + if (fd == -1) { + fd = open("/dev/random", O_WRONLY); + } + return write(fd, addr, 4) >= 0; +} + +uintptr_t Tools::GetBaseAddress(const char *name) { + uintptr_t base = 0; + char line[512]; + + FILE *f = fopen("/proc/self/maps", "r"); + + if (!f) { + return 0; + } + + while (fgets(line, sizeof line, f)) { + uintptr_t tmpBase; + char tmpName[256]; + if (sscanf(line, "%" PRIXPTR "-%*" PRIXPTR " %*s %*s %*s %*s %s", &tmpBase, tmpName) > 0) { + if (!strcmp(basename(tmpName), name)) { + base = tmpBase; + break; + } + } + } + + fclose(f); + return base; +} + +uintptr_t Tools::GetEndAddress(const char *name) { + uintptr_t end = 0; + char line[512]; + + FILE *f = fopen("/proc/self/maps", "r"); + + if (!f) { + return 0; + } + + bool found = false; + while (fgets(line, sizeof line, f)) { + uintptr_t tmpEnd; + char tmpName[256]; + if (sscanf(line, "%*" PRIXPTR "-%" PRIXPTR " %*s %*s %*s %*s %s", &tmpEnd, tmpName) > 0) { + if (!strcmp(basename(tmpName), name)) { + if (!found) { + found = true; + } + } else { + if (found) { + end = tmpEnd; + break; + } + } + } + } + + fclose(f); + return end; +} + +#define INRANGE(x, a, b) (x >= a && x <= b) +#define getBits(x) (INRANGE(x,'0','9') ? (x - '0') : ((x&(~0x20)) - 'A' + 0xa)) +#define getByte(x) (getBits(x[0]) << 4 | getBits(x[1])) + +uintptr_t Tools::FindPattern(const char *lib, const char *pattern) { + auto start = GetBaseAddress(lib); + if (!start) + return 0; + + auto end = GetEndAddress(lib); + if (!end) + return 0; + + auto curPat = reinterpret_cast(pattern); + uintptr_t firstMatch = 0; + for (uintptr_t pCur = start; pCur < end; ++pCur) { + if (*(uint8_t *) curPat == (uint8_t) '\?' || *(uint8_t *) pCur == getByte(curPat)) { + if (!firstMatch) { + firstMatch = pCur; + } + curPat += (*(uint16_t *) curPat == (uint16_t) '\?\?' || *(uint8_t *) curPat != (uint8_t) '\?') ? 2 : 1; + if (!*curPat) { + return firstMatch; + } + curPat++; + if (!*curPat) { + return firstMatch; + } + } else if (firstMatch) { + pCur = firstMatch; + curPat = reinterpret_cast(pattern); + firstMatch = 0; + } + } + return 0; +} + +std::string Tools::RandomString(const int len) { + static const char alphanumerics[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + srand((unsigned) time(0) * getpid()); + + std::string tmp; + tmp.reserve(len); + for (int i = 0; i < len; ++i) { + tmp += alphanumerics[rand() % (sizeof(alphanumerics) - 1)]; + } + return tmp; +} + +std::string Tools::GetPackageName(JNIEnv *env, jobject context) { + jclass contextClass = env->FindClass("android/content/Context"); + jmethodID getPackageNameId = env->GetMethodID(contextClass, "getPackageName", "()Ljava/lang/String;"); + + auto str = (jstring) env->CallObjectMethod(context, getPackageNameId); + return env->GetStringUTFChars(str, 0); +} diff --git a/app/src/main/jni/ByNameModding/Tools.h b/app/src/main/jni/ByNameModding/Tools.h new file mode 100644 index 0000000..dcf849b --- /dev/null +++ b/app/src/main/jni/ByNameModding/Tools.h @@ -0,0 +1,24 @@ +#include "Includes.h" +#include +#include + + +namespace Tools { + void Hook(void *target, void *replace, void **backup); + bool Read(void *addr, void *buffer, size_t length); + bool Write(void *addr, void *buffer, size_t length); + bool ReadAddr(void *addr, void *buffer, size_t length); + bool WriteAddr(void *addr, void *buffer, size_t length); + + bool PVM_ReadAddr(void *addr, void *buffer, size_t length); + bool PVM_WriteAddr(void *addr, void *buffer, size_t length); + + bool IsPtrValid(void *addr); + + uintptr_t GetBaseAddress(const char *name); + uintptr_t GetEndAddress(const char *name); + uintptr_t FindPattern(const char *lib, const char* pattern); + + std::string RandomString(const int len); + std::string GetPackageName(JNIEnv *env, jobject context); +} diff --git a/app/src/main/jni/ByNameModding/fake_dlfcn.cpp b/app/src/main/jni/ByNameModding/fake_dlfcn.cpp new file mode 100644 index 0000000..ea977e1 --- /dev/null +++ b/app/src/main/jni/ByNameModding/fake_dlfcn.cpp @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAG_NAME "dlfcn_ex" +#define LOG_DBG +#ifdef LOG_DBG +#define log_info(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG_NAME, (const char *) fmt, ##args) +#define log_err(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG_NAME, (const char *) fmt, ##args) +#define log_dbg log_info +#else +#define log_dbg(...) +#define log_info(fmt, args...) +#define log_err(fmt, args...) +#endif + +#ifdef __LP64__ +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#else +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#endif + +struct ctx { + void *load_addr; + void *dynstr; + void *dynsym; + int nsyms; + off_t bias; +}; + +extern "C" { + +static int fake_dlclose(void *handle) { + if (handle) { + struct ctx *ctx = (struct ctx *) handle; + if (ctx->dynsym) free(ctx->dynsym); /* we're saving dynsym and dynstr */ + if (ctx->dynstr) free(ctx->dynstr); /* from library file just in case */ + free(ctx); + } + return 0; +} + +/* flags are ignored */ +static void *fake_dlopen_with_path(const char *libpath, int flags) { + FILE *maps; + char buff[256], name[256]; + struct ctx *ctx = 0; + off_t load_addr, size; + int k, fd = -1, found = 0; + char *shoff; + Elf_Ehdr *elf = (Elf_Ehdr *) MAP_FAILED; + +#define fatal(fmt, args...) do { log_err(fmt,##args); goto err_exit; } while(0) + + maps = fopen("/proc/self/maps", "r"); + if (!maps) fatal("failed to open maps"); + + while (!found && fgets(buff, sizeof(buff), maps)) { + if (strstr(buff, libpath) && (strstr(buff, "r-xp") || strstr(buff, "r--p"))) found = 1; + } + fclose(maps); + + if (!found) fatal("%s not found in my userspace", libpath); + + if (sscanf(buff, "%lx-%*lx %*s %*s %*s %*s %s", &load_addr, name) != 2) + fatal("failed to read load address for %s", libpath); + + log_info("%s loaded in Android at 0x%08lx", libpath, load_addr); + + libpath = name; + + /* Now, mmap the same library once again */ + + fd = open(libpath, O_RDONLY); + if (fd < 0) fatal("failed to open %s", libpath); + + size = lseek(fd, 0, SEEK_END); + if (size <= 0) fatal("lseek() failed for %s", libpath); + + elf = (Elf_Ehdr *) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + fd = -1; + + if (elf == MAP_FAILED) fatal("mmap() failed for %s", libpath); + + ctx = (struct ctx *) calloc(1, sizeof(struct ctx)); + if (!ctx) fatal("no memory for %s", libpath); + + ctx->load_addr = (void *) load_addr; + shoff = ((char *) elf) + elf->e_shoff; + + for (k = 0; k < elf->e_shnum; k++, shoff += elf->e_shentsize) { + + Elf_Shdr *sh = (Elf_Shdr *) shoff; + log_dbg("%s: k=%d shdr=%p type=%x", __func__, k, sh, sh->sh_type); + + switch (sh->sh_type) { + + case SHT_DYNSYM: + if (ctx->dynsym) fatal("%s: duplicate DYNSYM sections", libpath); /* .dynsym */ + ctx->dynsym = malloc(sh->sh_size); + if (!ctx->dynsym) fatal("%s: no memory for .dynsym", libpath); + memcpy(ctx->dynsym, ((char *) elf) + sh->sh_offset, sh->sh_size); + ctx->nsyms = (sh->sh_size / sizeof(Elf_Sym)); + break; + + case SHT_STRTAB: + if (ctx->dynstr) break; /* .dynstr is guaranteed to be the first STRTAB */ + ctx->dynstr = malloc(sh->sh_size); + if (!ctx->dynstr) fatal("%s: no memory for .dynstr", libpath); + memcpy(ctx->dynstr, ((char *) elf) + sh->sh_offset, sh->sh_size); + break; + + case SHT_PROGBITS: + if (!ctx->dynstr || !ctx->dynsym) break; + /* won't even bother checking against the section name */ + ctx->bias = (off_t) sh->sh_addr - (off_t) sh->sh_offset; + k = elf->e_shnum; /* exit for */ + break; + } + } + + munmap(elf, size); + elf = 0; + + if (!ctx->dynstr || !ctx->dynsym) fatal("dynamic sections not found in %s", libpath); + +#undef fatal + + log_dbg("%s: ok, dynsym = %p, dynstr = %p", libpath, ctx->dynsym, ctx->dynstr); + + return ctx; + + err_exit: + if (fd >= 0) close(fd); + if (elf != MAP_FAILED) munmap(elf, size); + fake_dlclose(ctx); + return 0; +} + + +#if defined(__LP64__) +static const char *const kSystemLibDir = "/system/lib64/"; +static const char *const kOdmLibDir = "/odm/lib64/"; +static const char *const kVendorLibDir = "/vendor/lib64/"; +static const char *const kApexLibDir = "/apex/com.android.runtime/lib64/"; +static const char *const kApexArtNsLibDir = "/apex/com.android.art/lib64/"; +#else +static const char *const kSystemLibDir = "/system/lib/"; +static const char *const kOdmLibDir = "/odm/lib/"; +static const char *const kVendorLibDir = "/vendor/lib/"; +static const char *const kApexLibDir = "/apex/com.android.runtime/lib/"; +static const char *const kApexArtNsLibDir = "/apex/com.android.art/lib/"; +#endif + +static void *fake_dlopen(const char *filename, int flags) { + if (strlen(filename) > 0 && filename[0] == '/') { + return fake_dlopen_with_path(filename, flags); + } else { + char buf[512] = {0}; + void *handle = NULL; + //sysmtem + strcpy(buf, kSystemLibDir); + strcat(buf, filename); + handle = fake_dlopen_with_path(buf, flags); + if (handle) { + return handle; + } + + // apex in ns com.android.runtime + memset(buf, 0, sizeof(buf)); + strcpy(buf, kApexLibDir); + strcat(buf, filename); + handle = fake_dlopen_with_path(buf, flags); + if (handle) { + return handle; + } + + // apex in ns com.android.art + memset(buf, 0, sizeof(buf)); + strcpy(buf, kApexArtNsLibDir); + strcat(buf, filename); + handle = fake_dlopen_with_path(buf, flags); + if (handle) { + return handle; + } + + //odm + memset(buf, 0, sizeof(buf)); + strcpy(buf, kOdmLibDir); + strcat(buf, filename); + handle = fake_dlopen_with_path(buf, flags); + if (handle) { + return handle; + } + + //vendor + memset(buf, 0, sizeof(buf)); + strcpy(buf, kVendorLibDir); + strcat(buf, filename); + handle = fake_dlopen_with_path(buf, flags); + if (handle) { + return handle; + } + + return fake_dlopen_with_path(filename, flags); + } +} + +static void *fake_dlsym(void *handle, const char *name) { + int k; + struct ctx *ctx = (struct ctx *) handle; + Elf_Sym *sym = (Elf_Sym *) ctx->dynsym; + char *strings = (char *) ctx->dynstr; + + for (k = 0; k < ctx->nsyms; k++, sym++) + if (strcmp(strings + sym->st_name, name) == 0) { + /* NB: sym->st_value is an offset into the section for relocatables, + but a VMA for shared libs or exe files, so we have to subtract the bias */ + void *ret = (char *) ctx->load_addr + sym->st_value - ctx->bias; + log_info("%s found at %p", name, ret); + return ret; + } + return 0; +} + +static const char *fake_dlerror() { + return NULL; +} + +// =============== implementation for compat ========== +static int SDK_INT = -1; +static int get_sdk_level() { + if (SDK_INT > 0) { + return SDK_INT; + } + char sdk[PROP_VALUE_MAX] = {0};; + __system_property_get("ro.build.version.sdk", sdk); + SDK_INT = atoi(sdk); + return SDK_INT; +} + +int dlclose_ex(void *handle) { + if (get_sdk_level() >= 24) { + return fake_dlclose(handle); + } else { + return dlclose(handle); + } +} + +void *dlopen_ex(const char *filename, int flags) { + log_info("dlopen: %s", filename); + if (get_sdk_level() >= 24) { + return fake_dlopen(filename, flags); + } else { + return dlopen(filename, flags); + } +} + +void *dlsym_ex(void *handle, const char *symbol) { + if (get_sdk_level() >= 24) { + return fake_dlsym(handle, symbol); + } else { + return dlsym(handle, symbol); + } +} + +const char *dlerror_ex() { + if (get_sdk_level() >= 24) { + return fake_dlerror(); + } else { + return dlerror(); + } + } +} diff --git a/app/src/main/jni/ByNameModding/fake_dlfcn.h b/app/src/main/jni/ByNameModding/fake_dlfcn.h new file mode 100644 index 0000000..0782614 --- /dev/null +++ b/app/src/main/jni/ByNameModding/fake_dlfcn.h @@ -0,0 +1,20 @@ + +#ifndef DEXPOSED_DLFCN_H +#define DEXPOSED_DLFCN_H + +#include +#include +#include + +extern "C" { + +void *dlopen_ex(const char *filename, int flags); + +void *dlsym_ex(void *handle, const char *symbol); + +int dlclose_ex(void *handle); + +const char *dlerror_ex(); + +}; +#endif //DEXPOSED_DLFCN_H diff --git a/app/src/main/jni/Hook.h b/app/src/main/jni/Hook.h new file mode 100644 index 0000000..25ce09c --- /dev/null +++ b/app/src/main/jni/Hook.h @@ -0,0 +1,96 @@ +#include "AlguiLog.h" +#include "AlguiMemTool.h" +#include +#include +#include +#include +#include +#if defined(__aarch64__) +#include +#else +#include +#include +#endif + +//检查动态库是否已加载 +bool isLibraryLoaded(const char *libraryName) { + char line[512] = {0}; + FILE *fp = fopen("/proc/self/maps", "rt"); + if (fp != NULL) { + while (fgets(line, sizeof(line), fp)) { + std::string a = line; + if (strstr(line, libraryName)) { + return true; + } + } + fclose(fp); + } + return false; +} + +//动态库基址静态偏移到地址 +unsigned long getLibOffsetToAddr(const char *library,const char* offset) { + char filename[0xFF] = {0}, + buffer[1024] = {0}; + FILE *fp = NULL; + unsigned long address = 0; + + sprintf(filename, "/proc/self/maps"); + fp = fopen(filename, "rt"); + if (fp == NULL) { + perror("fopen"); + LOGI("hook", "maps打开失败"); + goto done; + } + + //按行读取当前进程的maps中的内容 + while (fgets(buffer, sizeof(buffer), fp)) { + //检查当前行是否包含目标库名 + if (strstr(buffer, library)) { + //获取该库的基址 + address = (unsigned long) strtoul(buffer, NULL, 16); // 从当前行提取出基址(16进制) + goto done; + } + } + +done: + if (fp) { + fclose(fp); + } + + if(address==0) + return 0; + //字符串偏移转换 + int base = 16; + uintptr_t of=0; + static_assert(sizeof(uintptr_t) == sizeof(unsigned long) + || sizeof(uintptr_t) == sizeof(unsigned long long), + "请使用字符串形式offset以处理转换"); + + if (sizeof(uintptr_t) == sizeof(unsigned long)) { + of = strtoul(offset, nullptr, base); + }else{ + of = strtoull(offset, nullptr, base); + } + + return (reinterpret_cast(address + of)); +} + + + + + + +void hook(void *offset, void* ptr, void **orig) +{ +#if defined(__aarch64__) + A64HookFunction(offset, ptr, orig); +#else + MSHookFunction(offset, ptr, orig); +#endif +} + +//通过函数相对库的偏移量进行HOOK +#define HOOK(lib, offset, newFun, oldFun) hook((void *)getLibOffsetToAddr(lib, offset), (void *)newFun, (void **)&oldFun) +//通过函数符号进行HOOK +#define HOOKSYM(lib, sym, newFun, oldFun) hook(dlsym(dlopen(lib, 4), sym), (void *)newFun, (void **)&oldFun) diff --git a/app/src/main/jni/Substrate/Buffer.hpp b/app/src/main/jni/Substrate/Buffer.hpp new file mode 100644 index 0000000..34d9df3 --- /dev/null +++ b/app/src/main/jni/Substrate/Buffer.hpp @@ -0,0 +1,38 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_BUFFER_HPP +#define SUBSTRATE_BUFFER_HPP + +#include + +template +_disused static _finline void MSWrite(uint8_t *&buffer, Type_ value) { + *reinterpret_cast(buffer) = value; + buffer += sizeof(Type_); +} + +_disused static _finline void MSWrite(uint8_t *&buffer, uint8_t *data, size_t size) { + memcpy(buffer, data, size); + buffer += size; +} + +#endif//SUBSTRATE_BUFFER_HPP diff --git a/app/src/main/jni/Substrate/CydiaSubstrate.h b/app/src/main/jni/Substrate/CydiaSubstrate.h new file mode 100644 index 0000000..bb806aa --- /dev/null +++ b/app/src/main/jni/Substrate/CydiaSubstrate.h @@ -0,0 +1,152 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_H_ +#define SUBSTRATE_H_ + +#ifdef __APPLE__ +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif + +#include +#include +#endif + +#include +#include + +#define _finline \ + inline __attribute__((__always_inline__)) +#define _disused \ + __attribute__((__unused__)) + +#define _extern \ + extern "C" __attribute__((__visibility__("default"))) + +#ifdef __cplusplus +#define _default(value) = value +#else +#define _default(value) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +bool MSHookProcess(pid_t pid, const char *library); + +typedef const void *MSImageRef; + +MSImageRef MSGetImageByName(const char *file); +void *MSFindSymbol(MSImageRef image, const char *name); + +void MSHookFunction(void *symbol, void *replace, void **result); + +#ifdef __APPLE__ +#ifdef __arm__ +__attribute__((__deprecated__)) +IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL)); +#endif +void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result); +#endif + +#ifdef SubstrateInternal +typedef void *SubstrateAllocatorRef; +typedef struct __SubstrateProcess *SubstrateProcessRef; +typedef struct __SubstrateMemory *SubstrateMemoryRef; + +SubstrateProcessRef SubstrateProcessCreate(SubstrateAllocatorRef allocator, pid_t pid); +void SubstrateProcessRelease(SubstrateProcessRef process); + +SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size); +void SubstrateMemoryRelease(SubstrateMemoryRef memory); +#endif + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +#ifdef SubstrateInternal +struct SubstrateHookMemory { + SubstrateMemoryRef handle_; + + SubstrateHookMemory(SubstrateProcessRef process, void *data, size_t size) : + handle_(SubstrateMemoryCreate(NULL, NULL, data, size)) + { + } + + ~SubstrateHookMemory() { + if (handle_ != NULL) + SubstrateMemoryRelease(handle_); + } +}; +#endif + + +template +static inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) { + MSHookFunction( + reinterpret_cast(symbol), + reinterpret_cast(replace), + reinterpret_cast(result) + ); +} + +template +static inline void MSHookFunction(Type_ *symbol, Type_ *replace) { + return MSHookFunction(symbol, replace, reinterpret_cast(NULL)); +} + +template +static inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) { + value = reinterpret_cast(MSFindSymbol(image, name)); +} + +template +static inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) { + Type_ *symbol; + MSHookSymbol(symbol, name); + return MSHookFunction(symbol, replace, result); +} + +#endif + +#define MSHook(type, name, args...) \ + _disused static type (*_ ## name)(args); \ + static type $ ## name(args) + +#ifdef __cplusplus +#define MSHake(name) \ + &$ ## name, &_ ## name +#else +#define MSHake(name) \ + &$ ## name, (void **) &_ ## name +#endif + + +#endif//SUBSTRATE_H_ diff --git a/app/src/main/jni/Substrate/SubstrateARM.hpp b/app/src/main/jni/Substrate/SubstrateARM.hpp new file mode 100644 index 0000000..02b3028 --- /dev/null +++ b/app/src/main/jni/Substrate/SubstrateARM.hpp @@ -0,0 +1,65 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_ARM_HPP +#define SUBSTRATE_ARM_HPP + +enum A$r { + A$r0, A$r1, A$r2, A$r3, + A$r4, A$r5, A$r6, A$r7, + A$r8, A$r9, A$r10, A$r11, + A$r12, A$r13, A$r14, A$r15, + A$sp = A$r13, + A$lr = A$r14, + A$pc = A$r15 +}; + +enum A$c { + A$eq, A$ne, A$cs, A$cc, + A$mi, A$pl, A$vs, A$vc, + A$hi, A$ls, A$ge, A$lt, + A$gt, A$le, A$al, + A$hs = A$cs, + A$lo = A$cc +}; + +#define A$mrs_rm_cpsr(rd) /* mrs rd, cpsr */ \ + (0xe10f0000 | ((rd) << 12)) +#define A$msr_cpsr_f_rm(rm) /* msr cpsr_f, rm */ \ + (0xe128f000 | (rm)) +#define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \ + (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs((int)(im))) +#define A$str_rd_$rn_im$(rd, rn, im) /* sr rd, [rn, #im] */ \ + (0xe5000000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im)) +#define A$sub_rd_rn_$im(rd, rn, im) /* sub, rd, rn, #im */ \ + (0xe2400000 | ((rn) << 16) | ((rd) << 12) | (im & 0xff)) +#define A$blx_rm(rm) /* blx rm */ \ + (0xe12fff30 | (rm)) +#define A$mov_rd_rm(rd, rm) /* mov rd, rm */ \ + (0xe1a00000 | ((rd) << 12) | (rm)) +#define A$ldmia_sp$_$rs$(rs) /* ldmia sp!, {rs} */ \ + (0xe8b00000 | (A$sp << 16) | (rs)) +#define A$stmdb_sp$_$rs$(rs) /* stmdb sp!, {rs} */ \ + (0xe9200000 | (A$sp << 16) | (rs)) +#define A$stmia_sp$_$r0$ 0xe8ad0001 /* stmia sp!, {r0} */ +#define A$bx_r0 0xe12fff10 /* bx r0 */ + +#endif//SUBSTRATE_ARM_HPP diff --git a/app/src/main/jni/Substrate/SubstrateDebug.cpp b/app/src/main/jni/Substrate/SubstrateDebug.cpp new file mode 100644 index 0000000..0f6dda0 --- /dev/null +++ b/app/src/main/jni/Substrate/SubstrateDebug.cpp @@ -0,0 +1,96 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#include "SubstrateHook.h" +#include "SubstrateDebug.hpp" + +#include +#include +#include + +_extern bool MSDebug; +bool MSDebug = false; + +static char _MSHexChar(uint8_t value) { + return value < 0x20 || value >= 0x80 ? '.' : value; +} + +#define HexWidth_ 16 +#define HexDepth_ 4 + +void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark) { + const uint8_t *data((const uint8_t *) vdata); + + size_t i(0), j; + + char d[256]; + size_t b(0); + d[0] = '\0'; + + while (i != size) { + if (i % HexWidth_ == 0) { + if (mark != NULL) + b += sprintf(d + b,"\n[%s] ", mark); + b += sprintf(d + b,"0x%.3zx:", i); + } + + b += sprintf(d + b, " "); + + for (size_t q(0); q != stride; ++q) + b += sprintf(d + b, "%.2x", data[i + stride - q - 1]); + + i += stride; + + for (size_t q(1); q != stride; ++q) + b += sprintf(d + b, " "); + + if (i % HexDepth_ == 0) + b += sprintf(d + b, " "); + + if (i % HexWidth_ == 0) { + b += sprintf(d + b, " "); + for (j = i - HexWidth_; j != i; ++j) + b += sprintf(d + b, "%c", _MSHexChar(data[j])); + + lprintf("%s", d); + b = 0; + d[0] = '\0'; + } + } + + if (i % HexWidth_ != 0) { + for (j = i % HexWidth_; j != HexWidth_; ++j) + b += sprintf(d + b, " "); + for (j = 0; j != (HexWidth_ - i % HexWidth_ + HexDepth_ - 1) / HexDepth_; ++j) + b += sprintf(d + b, " "); + b += sprintf(d + b, " "); + for (j = i / HexWidth_ * HexWidth_; j != i; ++j) + b += sprintf(d + b, "%c", _MSHexChar(data[j])); + + // lprintf("%s", d); + b = 0; + d[0] = '\0'; + } +} + +void MSLogHex(const void *vdata, size_t size, const char *mark) { + return MSLogHexEx(vdata, size, 1, mark); +} diff --git a/app/src/main/jni/Substrate/SubstrateDebug.hpp b/app/src/main/jni/Substrate/SubstrateDebug.hpp new file mode 100644 index 0000000..9c554c8 --- /dev/null +++ b/app/src/main/jni/Substrate/SubstrateDebug.hpp @@ -0,0 +1,33 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_DEBUG_HPP +#define SUBSTRATE_DEBUG_HPP + +#include "SubstrateLog.hpp" +#define lprintf(format, ...) \ + MSLog(MSLogLevelNotice, format, ## __VA_ARGS__) + +extern "C" bool MSDebug; +void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark = 0); +void MSLogHex(const void *vdata, size_t size, const char *mark = 0); + +#endif//SUBSTRATE_DEBUG_HPP diff --git a/app/src/main/jni/Substrate/SubstrateHook.cpp b/app/src/main/jni/Substrate/SubstrateHook.cpp new file mode 100644 index 0000000..83a8ede --- /dev/null +++ b/app/src/main/jni/Substrate/SubstrateHook.cpp @@ -0,0 +1,950 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#define SubstrateInternal + +#include "CydiaSubstrate.h" + +#include + +#define _trace() do { \ + MSLog(MSLogLevelNotice, "_trace(%u)", __LINE__); \ +} while (false) + +#if defined(__i386__) || defined(__x86_64__) + +#include "hde64.h" + +#endif + +#include "SubstrateDebug.hpp" + +#include +#include +#include + +#ifdef __arm__ +/* WebCore (ARM) PC-Relative: +X 1 ldr r*,[pc,r*] != + 2 fldd d*,[pc,#*] +X 5 str r*,[pc,r*] != + 8 flds s*,[pc,#*] + 400 ldr r*,[pc,r*] == + 515 add r*, pc,r* == +X 4790 ldr r*,[pc,#*] */ + +// x=0; while IFS= read -r line; do if [[ ${#line} -ne 0 && $line == +([^\;]): ]]; then x=2; elif [[ $line == ' +'* && $x -ne 0 ]]; then ((--x)); echo "$x${line}"; fi; done WebCore.pc +// grep pc WebCore.pc | cut -c 40- | sed -Ee 's/^ldr *(ip|r[0-9]*),\[pc,\#0x[0-9a-f]*\].*/ ldr r*,[pc,#*]/;s/^add *r[0-9]*,pc,r[0-9]*.*/ add r*, pc,r*/;s/^(st|ld)r *r([0-9]*),\[pc,r([0-9]*)\].*/ \1r r\2,[pc,r\3]/;s/^fld(s|d) *(s|d)[0-9]*,\[pc,#0x[0-9a-f]*].*/fld\1 \2*,[pc,#*]/' | sort | uniq -c | sort -n + +#include "SubstrateARM.hpp" + +#define T$Label(l, r) \ + (((r) - (l)) * 2 - 4 + ((l) % 2 == 0 ? 0 : 2)) + +#define T$pop_$r0$ 0xbc01 // pop {r0} +#define T$b(im) /* b im */ \ + (0xde00 | (im & 0xff)) +#define T$blx(rm) /* blx rm */ \ + (0x4780 | (rm << 3)) +#define T$bx(rm) /* bx rm */ \ + (0x4700 | (rm << 3)) +#define T$nop /* nop */ \ + (0x46c0) + +#define T$add_rd_rm(rd, rm) /* add rd, rm */ \ + (0x4400 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) +#define T$push_r(r) /* push r... */ \ + (0xb400 | (((r) & (1 << A$lr)) >> A$lr << 8) | ((r) & 0xff)) +#define T$pop_r(r) /* pop r... */ \ + (0xbc00 | (((r) & (1 << A$pc)) >> A$pc << 8) | ((r) & 0xff)) +#define T$mov_rd_rm(rd, rm) /* mov rd, rm */ \ + (0x4600 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) +#define T$ldr_rd_$rn_im_4$(rd, rn, im) /* ldr rd, [rn, #im * 4] */ \ + (0x6800 | (((im) & 0x1f) << 6) | ((rn) << 3) | (rd)) +#define T$ldr_rd_$pc_im_4$(rd, im) /* ldr rd, [PC, #im * 4] */ \ + (0x4800 | ((rd) << 8) | ((im) & 0xff)) +#define T$cmp_rn_$im(rn, im) /* cmp rn, #im */ \ + (0x2000 | ((rn) << 8) | ((im) & 0xff)) +#define T$it$_cd(cd, ms) /* it, cd */ \ + (0xbf00 | ((cd) << 4) | (ms)) +#define T$cbz$_rn_$im(op,rn,im) /* cbz rn, #im */ \ + (0xb100 | ((op) << 11) | (((im) & 0x40) >> 6 << 9) | (((im) & 0x3e) >> 1 << 3) | (rn)) +#define T$b$_$im(cond,im) /* b #im */ \ + (cond == A$al ? 0xe000 | (((im) >> 1) & 0x7ff) : 0xd000 | ((cond) << 8) | (((im) >> 1) & 0xff)) + +#define T1$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ + (0xf850 | ((im < 0 ? 0 : 1) << 7) | (rn)) +#define T2$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ + (((rt) << 12) | abs((int)(im))) + +#define T1$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ + (0xf3ef) +#define T2$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ + (0x8000 | ((rd) << 8)) + +#define T1$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ + (0xf380 | (rn)) +#define T2$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ + (0x8c00) +#define T$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ + (T2$msr_apsr_nzcvqg_rn(rn) << 16 | T1$msr_apsr_nzcvqg_rn(rn)) + +static inline bool A$pcrel$r(uint32_t ic) { + return (ic & 0x0c000000) == 0x04000000 && (ic & 0xf0000000) != 0xf0000000 && (ic & 0x000f0000) == 0x000f0000; +} + +static inline bool T$32bit$i(uint16_t ic) { + return ((ic & 0xe000) == 0xe000 && (ic & 0x1800) != 0x0000); +} + +static inline bool T$pcrel$cbz(uint16_t ic) { + return (ic & 0xf500) == 0xb100; +} + +static inline bool T$pcrel$b(uint16_t ic) { + return (ic & 0xf000) == 0xd000 && (ic & 0x0e00) != 0x0e00; +} + +static inline bool T2$pcrel$b(uint16_t *ic) { + return (ic[0] & 0xf800) == 0xf000 && (((ic[1] & 0xd000) == 0x9000 || (ic[1] & 0xd000) == 0x8000) && (ic[0] & 0x0380) != 0x0380); +} + +static inline bool T$pcrel$bl(uint16_t *ic) { + return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0xd000 || (ic[1] & 0xd001) == 0xc000); +} + +static inline bool T$pcrel$ldr(uint16_t ic) { + return (ic & 0xf800) == 0x4800; +} + +static inline bool T$pcrel$add(uint16_t ic) { + return (ic & 0xff78) == 0x4478; +} + +static inline bool T$pcrel$ldrw(uint16_t ic) { + return (ic & 0xff7f) == 0xf85f; +} + +static size_t MSGetInstructionWidthThumb(void *start) { + uint16_t *thumb(reinterpret_cast(start)); + return T$32bit$i(thumb[0]) ? 4 : 2; +} + +static size_t MSGetInstructionWidthARM(void *start) { + return 4; +} + +extern "C" size_t MSGetInstructionWidth(void *start) { + if ((reinterpret_cast(start) & 0x1) == 0) + return MSGetInstructionWidthARM(start); + else + return MSGetInstructionWidthThumb(reinterpret_cast(reinterpret_cast(start) & ~0x1)); +} + +static size_t SubstrateHookFunctionThumb(SubstrateProcessRef process, void *symbol, void *replace, void **result) { + if (symbol == NULL) + return 0; +printf("SubstrateHookFunctionThumb\n"); + uint16_t *area(reinterpret_cast(symbol)); + + unsigned align((reinterpret_cast(area) & 0x2) == 0 ? 0 : 1); + uint16_t *thumb(area + align); + + uint32_t *arm(reinterpret_cast(thumb + 2)); + uint16_t *trail(reinterpret_cast(arm + 2)); + + if ( + (align == 0 || area[0] == T$nop) && + thumb[0] == T$bx(A$pc) && + thumb[1] == T$nop && + arm[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8) + ) { + if (result != NULL) + *result = reinterpret_cast(arm[1]); + + SubstrateHookMemory code(process, arm + 1, sizeof(uint32_t) * 1); + + arm[1] = reinterpret_cast(replace); + + return sizeof(arm[0]); + } + + size_t required((trail - area) * sizeof(uint16_t)); + + size_t used(0); + while (used < required) + used += MSGetInstructionWidthThumb(reinterpret_cast(area) + used); + used = (used + sizeof(uint16_t) - 1) / sizeof(uint16_t) * sizeof(uint16_t); + + size_t blank((used - required) / sizeof(uint16_t)); + + uint16_t backup[used / sizeof(uint16_t)]; + memcpy(backup, area, used); + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHexEx(area, used + sizeof(uint16_t), 2, name); + } + + if (result != NULL) { + + size_t length(used); + for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) + if (T$pcrel$ldr(backup[offset])) + length += 3 * sizeof(uint16_t); + else if (T$pcrel$b(backup[offset])) + length += 6 * sizeof(uint16_t); + else if (T2$pcrel$b(backup + offset)) { + length += 5 * sizeof(uint16_t); + ++offset; + } else if (T$pcrel$bl(backup + offset)) { + length += 5 * sizeof(uint16_t); + ++offset; + } else if (T$pcrel$cbz(backup[offset])) { + length += 16 * sizeof(uint16_t); + } else if (T$pcrel$ldrw(backup[offset])) { + length += 4 * sizeof(uint16_t); + ++offset; + } else if (T$pcrel$add(backup[offset])) + length += 6 * sizeof(uint16_t); + else if (T$32bit$i(backup[offset])) + ++offset; + + unsigned pad((length & 0x2) == 0 ? 0 : 1); + length += (pad + 2) * sizeof(uint16_t) + 2 * sizeof(uint32_t); + + uint16_t *buffer(reinterpret_cast(mmap( + NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 + ))); + + if (buffer == MAP_FAILED) { + MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); + *result = NULL; + return 0; + } + + if (false) fail: { + munmap(buffer, length); + *result = NULL; + return 0; + } + + size_t start(pad), end(length / sizeof(uint16_t)); + uint32_t *trailer(reinterpret_cast(buffer + end)); + for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) { + if (T$pcrel$ldr(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t immediate : 8; + uint16_t rd : 3; + uint16_t : 5; + }; + } bits = {backup[offset+0]}; + + buffer[start+0] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+0, end-2) / 4); + buffer[start+1] = T$ldr_rd_$rn_im_4$(bits.rd, bits.rd, 0); + + // XXX: this code "works", but is "wrong": the mechanism is more complex than this + *--trailer = ((reinterpret_cast(area + offset) + 4) & ~0x2) + bits.immediate * 4; + + start += 2; + end -= 2; + } else if (T$pcrel$b(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t imm8 : 8; + uint16_t cond : 4; + uint16_t /*1101*/ : 4; + }; + } bits = {backup[offset+0]}; + + intptr_t jump(bits.imm8 << 1); + jump |= 1; + jump <<= 23; + jump >>= 23; + + buffer[start+0] = T$b$_$im(bits.cond, (end-6 - (start+0)) * 2 - 4); + + *--trailer = reinterpret_cast(area + offset) + 4 + jump; + *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + *--trailer = T$nop << 16 | T$bx(A$pc); + + start += 1; + end -= 6; + } else if (T2$pcrel$b(backup + offset)) { + union { + uint16_t value; + + struct { + uint16_t imm6 : 6; + uint16_t cond : 4; + uint16_t s : 1; + uint16_t : 5; + }; + } bits = {backup[offset+0]}; + + union { + uint16_t value; + + struct { + uint16_t imm11 : 11; + uint16_t j2 : 1; + uint16_t a : 1; + uint16_t j1 : 1; + uint16_t : 2; + }; + } exts = {backup[offset+1]}; + + intptr_t jump(1); + jump |= exts.imm11 << 1; + jump |= bits.imm6 << 12; + + if (exts.a) { + jump |= bits.s << 24; + jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; + jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; + jump |= bits.cond << 18; + jump <<= 7; + jump >>= 7; + } else { + jump |= bits.s << 20; + jump |= exts.j2 << 19; + jump |= exts.j1 << 18; + jump <<= 11; + jump >>= 11; + } + + buffer[start+0] = T$b$_$im(exts.a ? A$al : bits.cond, (end-6 - (start+0)) * 2 - 4); + + *--trailer = reinterpret_cast(area + offset) + 4 + jump; + *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + *--trailer = T$nop << 16 | T$bx(A$pc); + + ++offset; + start += 1; + end -= 6; + } else if (T$pcrel$bl(backup + offset)) { + union { + uint16_t value; + + struct { + uint16_t immediate : 10; + uint16_t s : 1; + uint16_t : 5; + }; + } bits = {backup[offset+0]}; + + union { + uint16_t value; + + struct { + uint16_t immediate : 11; + uint16_t j2 : 1; + uint16_t x : 1; + uint16_t j1 : 1; + uint16_t : 2; + }; + } exts = {backup[offset+1]}; + + int32_t jump(0); + jump |= bits.s << 24; + jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; + jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; + jump |= bits.immediate << 12; + jump |= exts.immediate << 1; + jump |= exts.x; + jump <<= 7; + jump >>= 7; + + buffer[start+0] = T$push_r(1 << A$r7); + buffer[start+1] = T$ldr_rd_$pc_im_4$(A$r7, ((end-2 - (start+1)) * 2 - 4 + 2) / 4); + buffer[start+2] = T$mov_rd_rm(A$lr, A$r7); + buffer[start+3] = T$pop_r(1 << A$r7); + buffer[start+4] = T$blx(A$lr); + + *--trailer = reinterpret_cast(area + offset) + 4 + jump; + + ++offset; + start += 5; + end -= 2; + } else if (T$pcrel$cbz(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t rn : 3; + uint16_t immediate : 5; + uint16_t : 1; + uint16_t i : 1; + uint16_t : 1; + uint16_t op : 1; + uint16_t : 4; + }; + } bits = {backup[offset+0]}; + + intptr_t jump(1); + jump |= bits.i << 6; + jump |= bits.immediate << 1; + + //jump <<= 24; + //jump >>= 24; + + unsigned rn(bits.rn); + unsigned rt(rn == A$r7 ? A$r6 : A$r7); + + buffer[start+0] = T$push_r(1 << rt); + buffer[start+1] = T1$mrs_rd_apsr(rt); + buffer[start+2] = T2$mrs_rd_apsr(rt); + buffer[start+3] = T$cbz$_rn_$im(bits.op, rn, (end-10 - (start+3)) * 2 - 4); + buffer[start+4] = T1$msr_apsr_nzcvqg_rn(rt); + buffer[start+5] = T2$msr_apsr_nzcvqg_rn(rt); + buffer[start+6] = T$pop_r(1 << rt); + + *--trailer = reinterpret_cast(area + offset) + 4 + jump; + *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + *--trailer = T$nop << 16 | T$bx(A$pc); + *--trailer = T$nop << 16 | T$pop_r(1 << rt); + *--trailer = T$msr_apsr_nzcvqg_rn(rt); + +#if 0 + if ((start & 0x1) == 0) + buffer[start++] = T$nop; + buffer[start++] = T$bx(A$pc); + buffer[start++] = T$nop; + + uint32_t *arm(reinterpret_cast(buffer + start)); + arm[0] = A$add(A$lr, A$pc, 1); + arm[1] = A$ldr_rd_$rn_im$(A$pc, A$pc, (trailer - arm) * sizeof(uint32_t) - 8); +#endif + + start += 7; + end -= 10; + } else if (T$pcrel$ldrw(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t : 7; + uint16_t u : 1; + uint16_t : 8; + }; + } bits = {backup[offset+0]}; + + union { + uint16_t value; + + struct { + uint16_t immediate : 12; + uint16_t rt : 4; + }; + } exts = {backup[offset+1]}; + + buffer[start+0] = T1$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start+0, end-2)); + buffer[start+1] = T2$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start+0, end-2)); + + buffer[start+2] = T1$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); + buffer[start+3] = T2$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); + + // XXX: this code "works", but is "wrong": the mechanism is more complex than this + *--trailer = ((reinterpret_cast(area + offset) + 4) & ~0x2) + (bits.u == 0 ? -exts.immediate : exts.immediate); + + ++offset; + start += 4; + end -= 2; + } else if (T$pcrel$add(backup[offset])) { + union { + uint16_t value; + + struct { + uint16_t rd : 3; + uint16_t rm : 3; + uint16_t h2 : 1; + uint16_t h1 : 1; + uint16_t : 8; + }; + } bits = {backup[offset+0]}; + + if (bits.h1) { + MSLog(MSLogLevelError, "MS:Error:pcrel(%u):add (rd > r7)", offset); + goto fail; + } + + unsigned rt(bits.rd == A$r7 ? A$r6 : A$r7); + + buffer[start+0] = T$push_r(1 << rt); + buffer[start+1] = T$mov_rd_rm(rt, (bits.h1 << 3) | bits.rd); + buffer[start+2] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+2, end-2) / 4); + buffer[start+3] = T$add_rd_rm((bits.h1 << 3) | bits.rd, rt); + buffer[start+4] = T$pop_r(1 << rt); + *--trailer = reinterpret_cast(area + offset) + 4; + + start += 5; + end -= 2; + } else if (T$32bit$i(backup[offset])) { + buffer[start++] = backup[offset]; + buffer[start++] = backup[++offset]; + } else { + buffer[start++] = backup[offset]; + } + } + + buffer[start++] = T$bx(A$pc); + buffer[start++] = T$nop; + + uint32_t *transfer = reinterpret_cast(buffer + start); + transfer[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + transfer[1] = reinterpret_cast(area + used / sizeof(uint16_t)) + 1; + + if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { + MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); + return 0; + } + + *result = reinterpret_cast(buffer + pad) + 1; + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", *result); + MSLogHexEx(buffer, length, 2, name); + } + + } + + { + SubstrateHookMemory code(process, area, used); + + if (align != 0) + area[0] = T$nop; + + thumb[0] = T$bx(A$pc); + thumb[1] = T$nop; + + arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + arm[1] = reinterpret_cast(replace); + + for (unsigned offset(0); offset != blank; ++offset) + trail[offset] = T$nop; + } + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHexEx(area, used + sizeof(uint16_t), 2, name); + } + + return used; +} + +static size_t SubstrateHookFunctionARM(SubstrateProcessRef process, void *symbol, void *replace, void **result) { + if (symbol == NULL) + return 0; + printf("SubstrateHookFunctionARM\n"); + uint32_t *area(reinterpret_cast(symbol)); + uint32_t *arm(area); + + const size_t used(8); + + uint32_t backup[used / sizeof(uint32_t)] = {arm[0], arm[1]}; + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHexEx(area, used + sizeof(uint32_t), 4, name); + } + + if (result != NULL) { + + if (backup[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8)) { + *result = reinterpret_cast(backup[1]); + + return sizeof(backup[0]); + } + + size_t length(used); + for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) + if (A$pcrel$r(backup[offset])) { + if ((backup[offset] & 0x02000000) == 0 || (backup[offset] & 0x0000f000 >> 12) != (backup[offset] & 0x0000000f)) + length += 2 * sizeof(uint32_t); + else + length += 4 * sizeof(uint32_t); + } + + length += 2 * sizeof(uint32_t); + + uint32_t *buffer(reinterpret_cast(mmap( + NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 + ))); + + if (buffer == MAP_FAILED) { + MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); + *result = NULL; + return 0; + } + + if (false) fail: { + munmap(buffer, length); + *result = NULL; + return 0; + } + + size_t start(0), end(length / sizeof(uint32_t)); + uint32_t *trailer(reinterpret_cast(buffer + end)); + for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) + if (A$pcrel$r(backup[offset])) { + union { + uint32_t value; + + struct { + uint32_t rm : 4; + uint32_t : 1; + uint32_t shift : 2; + uint32_t shiftamount : 5; + uint32_t rd : 4; + uint32_t rn : 4; + uint32_t l : 1; + uint32_t w : 1; + uint32_t b : 1; + uint32_t u : 1; + uint32_t p : 1; + uint32_t mode : 1; + uint32_t type : 2; + uint32_t cond : 4; + }; + } bits = {backup[offset+0]}, copy(bits); + + bool guard; + if (bits.mode == 0 || bits.rd != bits.rm) { + copy.rn = bits.rd; + guard = false; + } else { + copy.rn = bits.rm != A$r0 ? A$r0 : A$r1; + guard = true; + } + + if (guard) + buffer[start++] = A$stmdb_sp$_$rs$((1 << copy.rn)); + + buffer[start+0] = A$ldr_rd_$rn_im$(copy.rn, A$pc, (end-1 - (start+0)) * 4 - 8); + buffer[start+1] = copy.value; + + start += 2; + + if (guard) + buffer[start++] = A$ldmia_sp$_$rs$((1 << copy.rn)); + + *--trailer = reinterpret_cast(area + offset) + 8; + end -= 1; + } else + buffer[start++] = backup[offset]; + + buffer[start+0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + buffer[start+1] = reinterpret_cast(area + used / sizeof(uint32_t)); + + if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { + MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); + goto fail; + } + + *result = buffer; + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", *result); + MSLogHexEx(buffer, length, 4, name); + } + + } + + { + SubstrateHookMemory code(process, symbol, used); + + arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); + arm[1] = reinterpret_cast(replace); + } + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHexEx(area, used + sizeof(uint32_t), 4, name); + } + + return used; +} + +static size_t SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) { + if (MSDebug) + MSLog(MSLogLevelNotice, "SubstrateHookFunction(%p, %p, %p, %p)\n", process, symbol, replace, result); + if ((reinterpret_cast(symbol) & 0x1) == 0) + return SubstrateHookFunctionARM(process, symbol, replace, result); + else + return SubstrateHookFunctionThumb(process, reinterpret_cast(reinterpret_cast(symbol) & ~0x1), replace, result); +} +#endif + +#if defined(__i386__) || defined(__x86_64__) + +#include "SubstrateX86.hpp" + +static size_t MSGetInstructionWidthIntel(void *start) { + hde64s decode; + return hde64_disasm(start, &decode); +} + +static void +SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) { + if (MSDebug) + MSLog(MSLogLevelNotice, "MSHookFunction(%p, %p, %p)\n", symbol, replace, result); + if (symbol == NULL) + return; + + uintptr_t source(reinterpret_cast(symbol)); + uintptr_t target(reinterpret_cast(replace)); + + uint8_t *area(reinterpret_cast(symbol)); + + size_t required(MSSizeOfJump(target, source)); + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHex(area, 32, name); + } + + size_t used(0); + while (used < required) { + size_t width(MSGetInstructionWidthIntel(area + used)); + if (width == 0) { + //MSLog(MSLogLevelError, "MS:Error:MSGetInstructionWidthIntel(%p) == 0", area + used); + return; + } + + used += width; + } + + size_t blank(used - required); + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHex(area, used + sizeof(uint16_t), name); + } + + uint8_t backup[used]; + memcpy(backup, area, used); + + if (result != NULL) { + + if (backup[0] == 0xe9) { + *result = reinterpret_cast(source + 5 + + *reinterpret_cast(backup + 1)); + return; + } + + if (!ia32 && backup[0] == 0xff && backup[1] == 0x25) { + *result = *reinterpret_cast(source + 6 + + *reinterpret_cast(backup + 2)); + return; + } + + size_t length(used + MSSizeOfJump(source + used)); + + for (size_t offset(0), width; offset != used; offset += width) { + hde64s decode; + hde64_disasm(backup + offset, &decode); + width = decode.len; + //_assert(width != 0 && offset + width <= used); + +#ifdef __LP64__ + if ((decode.modrm & 0xc7) == 0x05) { + if (decode.opcode == 0x8b) { + void *destiny(area + offset + width + int32_t(decode.disp.disp32)); + uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); + length -= decode.len; + length += MSSizeOfPushPointer(destiny); + length += MSSizeOfPop(reg); + length += MSSizeOfMove64(); + } else { + MSLog(MSLogLevelError, "MS:Error: Unknown RIP-Relative (%.2x %.2x)", decode.opcode, decode.opcode2); + continue; + } + } else +#endif + + if (backup[offset] == 0xe8) { + int32_t relative(*reinterpret_cast(backup + offset + 1)); + void *destiny(area + offset + decode.len + relative); + + if (relative == 0) { + length -= decode.len; + length += MSSizeOfPushPointer(destiny); + } else { + length += MSSizeOfSkip(); + length += MSSizeOfJump(destiny); + } + } else if (backup[offset] == 0xeb) { + length -= decode.len; + length += MSSizeOfJump(area + offset + decode.len + + *reinterpret_cast(backup + offset + 1)); + } else if (backup[offset] == 0xe9) { + length -= decode.len; + length += MSSizeOfJump(area + offset + decode.len + + *reinterpret_cast(backup + offset + 1)); + } else if ( + backup[offset] == 0xe3 || + (backup[offset] & 0xf0) == 0x70 + // XXX: opcode2 & 0xf0 is 0x80? + ) { + length += decode.len; + length += MSSizeOfJump(area + offset + decode.len + + *reinterpret_cast(backup + offset + 1)); + } + } + + uint8_t *buffer(reinterpret_cast(mmap( + NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 + ))); + + if (buffer == MAP_FAILED) { + MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); + *result = NULL; + return; + } + + if (false) + fail: + { + munmap(buffer, length); + *result = NULL; + return; + } + + { + uint8_t *current(buffer); + + for (size_t offset(0), width; offset != used; offset += width) { + hde64s decode; + hde64_disasm(backup + offset, &decode); + width = decode.len; + //_assert(width != 0 && offset + width <= used); + +#ifdef __LP64__ + if ((decode.modrm & 0xc7) == 0x05) { + if (decode.opcode == 0x8b) { + void *destiny(area + offset + width + int32_t(decode.disp.disp32)); + uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); + MSPushPointer(current, destiny); + MSWritePop(current, reg); + MSWriteMove64(current, reg, reg); + } else { + MSLog(MSLogLevelError, "MS:Error: Unknown RIP-Relative (%.2x %.2x)", decode.opcode, decode.opcode2); + goto copy; + } + } else +#endif + + if (backup[offset] == 0xe8) { + int32_t relative(*reinterpret_cast(backup + offset + 1)); + if (relative == 0) + MSPushPointer(current, area + offset + decode.len); + else { + MSWrite(current, 0xe8); + MSWrite(current, MSSizeOfSkip()); + void *destiny(area + offset + decode.len + relative); + MSWriteSkip(current, MSSizeOfJump(destiny, current + MSSizeOfSkip())); + MSWriteJump(current, destiny); + } + } else if (backup[offset] == 0xeb) + MSWriteJump(current, area + offset + decode.len + + *reinterpret_cast(backup + offset + 1)); + else if (backup[offset] == 0xe9) + MSWriteJump(current, area + offset + decode.len + + *reinterpret_cast(backup + offset + 1)); + else if ( + backup[offset] == 0xe3 || + (backup[offset] & 0xf0) == 0x70 + ) { + MSWrite(current, backup[offset]); + MSWrite(current, 2); + MSWrite(current, 0xeb); + void *destiny(area + offset + decode.len + + *reinterpret_cast(backup + offset + 1)); + MSWrite(current, MSSizeOfJump(destiny, current + 1)); + MSWriteJump(current, destiny); + } else +#ifdef __LP64__ + copy: +#endif + { + MSWrite(current, backup + offset, width); + } + } + + MSWriteJump(current, area + used); + } + + if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { + MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); + goto fail; + } + + *result = buffer; + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", *result); + MSLogHex(buffer, length, name); + } + + } + + { + SubstrateHookMemory code(process, area, used); + uint8_t *current(area); + MSWriteJump(current, target); + for (unsigned offset(0); offset != blank; ++offset) + MSWrite(current, 0x90); + } + + if (MSDebug) { + char name[16]; + sprintf(name, "%p", area); + MSLogHex(area, used + sizeof(uint16_t), name); + } +} + +#endif + +void MSHookFunction(void *symbol, void *replace, void **result) { +#if defined(__i386__) || defined(__arm__) + SubstrateHookFunction(NULL, symbol, replace, result); +#endif +} + +#if defined(__APPLE__) && defined(__arm__) +_extern void _Z14MSHookFunctionPvS_PS_(void *symbol, void *replace, void **result) { + return MSHookFunction(symbol, replace, result); +} +#endif diff --git a/app/src/main/jni/Substrate/SubstrateHook.h b/app/src/main/jni/Substrate/SubstrateHook.h new file mode 100644 index 0000000..ab68a60 --- /dev/null +++ b/app/src/main/jni/Substrate/SubstrateHook.h @@ -0,0 +1,19 @@ +#ifndef __SUBSTRATEHOOK_H__ +#define __SUBSTRATEHOOK_H__ + + +#include + +#define _extern extern "C" __attribute__((__visibility__("hidden"))) + +#ifdef __cplusplus +extern "C" { +#endif + +void MSHookFunction(void *symbol, void *replace, void **result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/src/main/jni/Substrate/SubstrateLog.hpp b/app/src/main/jni/Substrate/SubstrateLog.hpp new file mode 100644 index 0000000..3e57280 --- /dev/null +++ b/app/src/main/jni/Substrate/SubstrateLog.hpp @@ -0,0 +1,40 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_LOG_HPP +#define SUBSTRATE_LOG_HPP + +#if 0 +#include + +#define MSLog(level, format, ...) ((void)__android_log_print(level, "NNNN", format, __VA_ARGS__)) + +#define MSLogLevelNotice ANDROID_LOG_INFO +#define MSLogLevelWarning ANDROID_LOG_WARN +#define MSLogLevelError ANDROID_LOG_ERROR + +#else + +#define MSLog(level, format, ...) printf(format, __VA_ARGS__) + +#endif + +#endif//SUBSTRATE_LOG_HPP diff --git a/app/src/main/jni/Substrate/SubstratePosixMemory.cpp b/app/src/main/jni/Substrate/SubstratePosixMemory.cpp new file mode 100644 index 0000000..15b2545 --- /dev/null +++ b/app/src/main/jni/Substrate/SubstratePosixMemory.cpp @@ -0,0 +1,75 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#define SubstrateInternal +#include "CydiaSubstrate.h" +#include "SubstrateLog.hpp" + +#include + +#include +#include +#include + +extern "C" void __clear_cache (void *beg, void *end); + +struct __SubstrateMemory { + void *address_; + size_t width_; + + __SubstrateMemory(void *address, size_t width) : + address_(address), + width_(width) + { + } +}; + +extern "C" SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size) { + if (allocator != NULL) { + MSLog(MSLogLevelError, "MS:Error:allocator != %d", 0); + return NULL; + } + + if (size == 0) + return NULL; + + int page(getpagesize()); + + uintptr_t base(reinterpret_cast(data) / page * page); + size_t width(((reinterpret_cast(data) + size - 1) / page + 1) * page - base); + void *address(reinterpret_cast(base)); + + if (mprotect(address, width, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { + MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); + return NULL; + } + + return new __SubstrateMemory(address, width); +} + +extern "C" void SubstrateMemoryRelease(SubstrateMemoryRef memory) { + if (mprotect(memory->address_, memory->width_, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) + MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); + + __clear_cache(reinterpret_cast(memory->address_), reinterpret_cast(memory->address_) + memory->width_); + + delete memory; +} diff --git a/app/src/main/jni/Substrate/SubstrateX86.hpp b/app/src/main/jni/Substrate/SubstrateX86.hpp new file mode 100644 index 0000000..ffe2b06 --- /dev/null +++ b/app/src/main/jni/Substrate/SubstrateX86.hpp @@ -0,0 +1,200 @@ +/* Cydia Substrate - Powerful Code Insertion Platform + * Copyright (C) 2008-2011 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Substrate is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Substrate is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substrate. If not, see . +**/ +/* }}} */ + +#ifndef SUBSTRATE_X86_HPP +#define SUBSTRATE_X86_HPP + +#include "Buffer.hpp" + +#ifdef __LP64__ +static const bool ia32 = false; +#else +static const bool ia32 = true; +#endif + +enum I$r { + I$rax, I$rcx, I$rdx, I$rbx, + I$rsp, I$rbp, I$rsi, I$rdi, + I$r8, I$r9, I$r10, I$r11, + I$r12, I$r13, I$r14, I$r15, +}; + +_disused static bool MSIs32BitOffset(uintptr_t target, uintptr_t source) { + intptr_t offset(target - source); + return int32_t(offset) == offset; +} + +_disused static size_t MSSizeOfSkip() { + return 5; +} + +_disused static size_t MSSizeOfPushPointer(uintptr_t target) { + return uint64_t(target) >> 32 == 0 ? 5 : 13; +} + +_disused static size_t MSSizeOfPushPointer(void *target) { + return MSSizeOfPushPointer(reinterpret_cast(target)); +} + +_disused static size_t MSSizeOfJump(bool blind, uintptr_t target, uintptr_t source = 0) { + if (ia32 || !blind && MSIs32BitOffset(target, source + 5)) + return MSSizeOfSkip(); + else + return MSSizeOfPushPointer(target) + 1; +} + +_disused static size_t MSSizeOfJump(uintptr_t target, uintptr_t source) { + return MSSizeOfJump(false, target, source); +} + +_disused static size_t MSSizeOfJump(uintptr_t target) { + return MSSizeOfJump(true, target); +} + +_disused static size_t MSSizeOfJump(void *target, void *source) { + return MSSizeOfJump(reinterpret_cast(target), reinterpret_cast(source)); +} + +_disused static size_t MSSizeOfJump(void *target) { + return MSSizeOfJump(reinterpret_cast(target)); +} + +_disused static void MSWriteSkip(uint8_t *¤t, ssize_t size) { + MSWrite(current, 0xe9); + MSWrite(current, size); +} + +_disused static void MSPushPointer(uint8_t *¤t, uintptr_t target) { + MSWrite(current, 0x68); + MSWrite(current, target); + + if (uint32_t high = uint64_t(target) >> 32) { + MSWrite(current, 0xc7); + MSWrite(current, 0x44); + MSWrite(current, 0x24); + MSWrite(current, 0x04); + MSWrite(current, high); + } +} + +_disused static void MSPushPointer(uint8_t *¤t, void *target) { + return MSPushPointer(current, reinterpret_cast(target)); +} + +_disused static void MSWriteCall(uint8_t *¤t, I$r target) { + if (target >> 3 != 0) + MSWrite(current, 0x40 | (target & 0x08) >> 3); + MSWrite(current, 0xff); + MSWrite(current, 0xd0 | target & 0x07); +} + +_disused static void MSWriteCall(uint8_t *¤t, uintptr_t target) { + uintptr_t source(reinterpret_cast(current)); + + if (ia32 || MSIs32BitOffset(target, source + 5)) { + MSWrite(current, 0xe8); + MSWrite(current, target - (source + 5)); + } else { + MSPushPointer(current, target); + + MSWrite(current, 0x83); + MSWrite(current, 0xc4); + MSWrite(current, 0x08); + + MSWrite(current, 0x67); + MSWrite(current, 0xff); + MSWrite(current, 0x54); + MSWrite(current, 0x24); + MSWrite(current, 0xf8); + } +} + +template +_disused static void MSWriteCall(uint8_t *¤t, Type_ *target) { + return MSWriteCall(current, reinterpret_cast(target)); +} + +_disused static void MSWriteJump(uint8_t *¤t, uintptr_t target) { + uintptr_t source(reinterpret_cast(current)); + + if (ia32 || MSIs32BitOffset(target, source + 5)) + MSWriteSkip(current, target - (source + 5)); + else { + MSPushPointer(current, target); + MSWrite(current, 0xc3); + } +} + +_disused static void MSWriteJump(uint8_t *¤t, void *target) { + return MSWriteJump(current, reinterpret_cast(target)); +} + +_disused static void MSWriteJump(uint8_t *¤t, I$r target) { + if (target >> 3 != 0) + MSWrite(current, 0x40 | (target & 0x08) >> 3); + MSWrite(current, 0xff); + MSWrite(current, 0xe0 | target & 0x07); +} + +_disused static void MSWritePop(uint8_t *¤t, uint8_t target) { + if (target >> 3 != 0) + MSWrite(current, 0x40 | (target & 0x08) >> 3); + MSWrite(current, 0x58 | target & 0x07); +} + +_disused static size_t MSSizeOfPop(uint8_t target) { + return target >> 3 != 0 ? 2 : 1; +} + +_disused static void MSWritePush(uint8_t *¤t, I$r target) { + if (target >> 3 != 0) + MSWrite(current, 0x40 | (target & 0x08) >> 3); + MSWrite(current, 0x50 | target & 0x07); +} + +_disused static void MSWriteAdd(uint8_t *¤t, I$r target, uint8_t source) { + MSWrite(current, 0x83); + MSWrite(current, 0xc4 | target & 0x07); + MSWrite(current, source); +} + +_disused static void MSWriteSet64(uint8_t *¤t, I$r target, uintptr_t source) { + MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2); + MSWrite(current, 0xb8 | target & 0x7); + MSWrite(current, source); +} + +template +_disused static void MSWriteSet64(uint8_t *¤t, I$r target, Type_ *source) { + return MSWriteSet64(current, target, reinterpret_cast(source)); +} + +_disused static void MSWriteMove64(uint8_t *¤t, uint8_t source, uint8_t target) { + MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2 | (source & 0x08) >> 3); + MSWrite(current, 0x8b); + MSWrite(current, (target & 0x07) << 3 | source & 0x07); +} + +_disused static size_t MSSizeOfMove64() { + return 3; +} + +#endif//SUBSTRATE_X86_HPP diff --git a/app/src/main/jni/Substrate/SymbolFinder.cpp b/app/src/main/jni/Substrate/SymbolFinder.cpp new file mode 100644 index 0000000..832f07d --- /dev/null +++ b/app/src/main/jni/Substrate/SymbolFinder.cpp @@ -0,0 +1,432 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "SymbolFinder.h" + +#define TAG "MSHook" +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) +/* memory map for libraries */ +#define MAX_NAME_LEN 256 +#define MEMORY_ONLY "[memory]" +struct mm { + char name[MAX_NAME_LEN]; + unsigned long start, end; +}; + +typedef struct symtab *symtab_t; +struct symlist { + Elf32_Sym *sym; /* symbols */ + char *str; /* symbol strings */ + unsigned num; /* number of symbols */ +}; +struct symtab { + struct symlist *st; /* "static" symbols */ + struct symlist *dyn; /* dynamic symbols */ +}; + +static void *xmalloc(size_t size) { + void *p; + p = malloc(size); + if (!p) { + printf("Out of memory\n"); + exit(1); + } + return p; +} + +static int my_pread(int fd, void *buf, size_t count, off_t offset) { + lseek(fd, offset, SEEK_SET); + return read(fd, buf, count); +} + +static struct symlist *get_syms(int fd, Elf32_Shdr *symh, Elf32_Shdr *strh) { + struct symlist *sl, *ret; + int rv; + + ret = NULL; + sl = (struct symlist *) xmalloc(sizeof(struct symlist)); + sl->str = NULL; + sl->sym = NULL; + + /* sanity */ + if (symh->sh_size % sizeof(Elf32_Sym)) { + //printf("elf_error\n"); + goto out; + } + + /* symbol table */ + sl->num = symh->sh_size / sizeof(Elf32_Sym); + sl->sym = (Elf32_Sym *) xmalloc(symh->sh_size); + rv = my_pread(fd, sl->sym, symh->sh_size, symh->sh_offset); + if (0 > rv) { + //perror("read"); + goto out; + } + if (rv != symh->sh_size) { + //printf("elf error\n"); + goto out; + } + + /* string table */ + sl->str = (char *) xmalloc(strh->sh_size); + rv = my_pread(fd, sl->str, strh->sh_size, strh->sh_offset); + if (0 > rv) { + //perror("read"); + goto out; + } + if (rv != strh->sh_size) { + //printf("elf error"); + goto out; + } + + ret = sl; + out: + return ret; +} + +static int do_load(int fd, symtab_t symtab) { + int rv; + size_t size; + Elf32_Ehdr ehdr; + Elf32_Shdr *shdr = NULL, *p; + Elf32_Shdr *dynsymh, *dynstrh; + Elf32_Shdr *symh, *strh; + char *shstrtab = NULL; + int i; + int ret = -1; + + /* elf header */ + rv = read(fd, &ehdr, sizeof(ehdr)); + if (0 > rv) { + LOGD("read\n"); + goto out; + } + if (rv != sizeof(ehdr)) { + LOGD("elf error 1\n"); + goto out; + } + if (strncmp((const char *) ELFMAG, (const char *) ehdr.e_ident, SELFMAG)) { /* sanity */ + LOGD("not an elf\n"); + goto out; + } + if (sizeof(Elf32_Shdr) != ehdr.e_shentsize) { /* sanity */ + LOGD("elf error 2\n"); + goto out; + } + + /* section header table */ + size = ehdr.e_shentsize * ehdr.e_shnum; + shdr = (Elf32_Shdr *) xmalloc(size); + rv = my_pread(fd, shdr, size, ehdr.e_shoff); + if (0 > rv) { + LOGD("read\n"); + goto out; + } + if (rv != size) { + LOGD("elf error 3 %d %d\n", rv, size); + goto out; + } + + /* section header string table */ + size = shdr[ehdr.e_shstrndx].sh_size; + shstrtab = (char *) xmalloc(size); + rv = my_pread(fd, shstrtab, size, shdr[ehdr.e_shstrndx].sh_offset); + if (0 > rv) { + LOGD("read\n"); + goto out; + } + if (rv != size) { + LOGD("elf error 4 %d %d\n", rv, size); + goto out; + } + + /* symbol table headers */ + symh = dynsymh = NULL; + strh = dynstrh = NULL; + for (i = 0, p = shdr; i < ehdr.e_shnum; i++, p++) + if (SHT_SYMTAB == p->sh_type) { + if (symh) { + LOGD("too many symbol tables\n"); + goto out; + } + symh = p; + } else if (SHT_DYNSYM == p->sh_type) { + if (dynsymh) { + LOGD("too many symbol tables\n"); + goto out; + } + dynsymh = p; + } else if (SHT_STRTAB == p->sh_type + && !strncmp(shstrtab + p->sh_name, ".strtab", 7)) { + if (strh) { + LOGD("too many string tables\n"); + goto out; + } + strh = p; + } else if (SHT_STRTAB == p->sh_type + && !strncmp(shstrtab + p->sh_name, ".dynstr", 7)) { + if (dynstrh) { + LOGD("too many string tables\n"); + goto out; + } + dynstrh = p; + } + /* sanity checks */ + if ((!dynsymh && dynstrh) || (dynsymh && !dynstrh)) { + LOGD("bad dynamic symbol table\n"); + goto out; + } + if ((!symh && strh) || (symh && !strh)) { + LOGD("bad symbol table\n"); + goto out; + } + if (!dynsymh && !symh) { + LOGD("no symbol table\n"); + goto out; + } + + /* symbol tables */ + if (dynsymh) + symtab->dyn = get_syms(fd, dynsymh, dynstrh); + if (symh) + symtab->st = get_syms(fd, symh, strh); + ret = 0; + out: + free(shstrtab); + free(shdr); + return ret; +} + +static symtab_t load_symtab(char *filename) { + int fd; + symtab_t symtab; + + symtab = (symtab_t) xmalloc(sizeof(*symtab)); + memset(symtab, 0, sizeof(*symtab)); + + fd = open(filename, O_RDONLY); + if (0 > fd) { + LOGE("%s open\n", __func__); + return NULL; + } + if (0 > do_load(fd, symtab)) { + LOGE("Error ELF parsing %s\n", filename); + free(symtab); + symtab = NULL; + } + close(fd); + return symtab; +} + +static int load_memmap(pid_t pid, struct mm *mm, int *nmmp) { + size_t buf_size = 0x40000; + char *p_buf = (char *) malloc(buf_size); // increase this if needed for larger "maps" + char name[MAX_NAME_LEN] = {0}; + char *p; + unsigned long start, end; + struct mm *m; + int nmm = 0; + int fd, rv; + int i; + + sprintf(p_buf, "/proc/%d/maps", pid); + fd = open(p_buf, O_RDONLY); + if (0 > fd) { + LOGE("Can't open %s for reading\n", p_buf); + free(p_buf); + return -1; + } + + /* Zero to ensure data is null terminated */ + memset(p_buf, 0, buf_size); + + p = p_buf; + while (1) { + rv = read(fd, p, buf_size - (p - p_buf)); + if (0 > rv) { + LOGE("%s read", __FUNCTION__); + free(p_buf); + return -1; + } + if (0 == rv) + break; + p += rv; + if (p - p_buf >= buf_size) { + LOGE("Too many memory mapping\n"); + free(p_buf); + return -1; + } + } + close(fd); + + p = strtok(p_buf, "\n"); + m = mm; + while (p) { + /* parse current map line */ + rv = sscanf(p, "%08lx-%08lx %*s %*s %*s %*s %s\n", &start, &end, name); + + p = strtok(NULL, "\n"); + + if (rv == 2) { + m = &mm[nmm++]; + m->start = start; + m->end = end; + memcpy(m->name, MEMORY_ONLY, sizeof(MEMORY_ONLY)); + continue; + } + + /* search backward for other mapping with same name */ + for (i = nmm - 1; i >= 0; i--) { + m = &mm[i]; + if (!strcmp(m->name, name)) + break; + } + + if (i >= 0) { + if (start < m->start) + m->start = start; + if (end > m->end) + m->end = end; + } else { + /* new entry */ + m = &mm[nmm++]; + m->start = start; + m->end = end; + memcpy(m->name, name, strlen(name)); + } + } + + *nmmp = nmm; + free(p_buf); + return 0; +} + +/* Find libc in MM, storing no more than LEN-1 chars of + its name in NAME and set START to its starting + address. If libc cannot be found return -1 and + leave NAME and START untouched. Otherwise return 0 + and null-terminated NAME. */ +static int find_libname(const char *libn, char *name, int len, unsigned long *start, + struct mm *mm, int nmm) { + int i; + struct mm *m; + char *p; + for (i = 0, m = mm; i < nmm; i++, m++) { + if (!strcmp(m->name, MEMORY_ONLY)) + continue; + p = strrchr(m->name, '/'); + if (!p) + continue; + p++; + if (strncmp(libn, p, strlen(libn))) + continue; + p += strlen(libn); + + /* here comes our crude test -> 'libc.so' or 'libc-[0-9]' */ + if (!strncmp("so", p, 2) || 1) // || (p[0] == '-' && isdigit(p[1]))) + break; + } + if (i >= nmm) + /* not found */ + return -1; + + *start = m->start; + strncpy(name, m->name, len); + if (strlen(m->name) >= len) + name[len - 1] = '\0'; + + mprotect((void *) m->start, m->end - m->start, + PROT_READ | PROT_WRITE | PROT_EXEC); + return 0; +} + +static int lookup2(struct symlist *sl, unsigned char type, char *name, + unsigned long *val) { + Elf32_Sym *p; + int len; + int i; + + len = strlen(name); + for (i = 0, p = sl->sym; i < sl->num; i++, p++) { + //LOGD("name: %s %x\n", sl->str+p->st_name, p->st_value) + if (!strncmp(sl->str + p->st_name, name, len) + && *(sl->str + p->st_name + len) == 0 + && ELF32_ST_TYPE(p->st_info) == type) { + //if (p->st_value != 0) { + *val = p->st_value; + return 0; + //} + } + } + return -1; +} + +static int lookup_sym(symtab_t s, unsigned char type, char *name, + unsigned long *val) { + if (s->dyn && !lookup2(s->dyn, type, name, val)) + return 0; + if (s->st && !lookup2(s->st, type, name, val)) + return 0; + return -1; +} + +static int lookup_func_sym(symtab_t s, char *name, unsigned long *val) { + return lookup_sym(s, STT_FUNC, name, val); +} + +int find_name(pid_t pid, const char *name, const char *libn, + unsigned long *addr) { + struct mm mm[1000] = {0}; + unsigned long libcaddr; + int nmm; + char libc[1024] = {0}; + symtab_t s; + + if (0 > load_memmap(pid, mm, &nmm)) { + LOGD("cannot read memory map\n"); + return -1; + } + if (0 + > find_libname((char *) libn, (char *) libc, sizeof(libc), + &libcaddr, mm, nmm)) { + LOGD("cannot find lib: %s\n", libn); + return -1; + } + //LOGD("lib: >%s<\n", libc) + s = load_symtab(libc); + if (!s) { + LOGD("cannot read symbol table\n"); + return -1; + } + if (0 > lookup_func_sym(s, (char *) name, addr)) { + LOGD("cannot find function: %s\n", name); + return -1; + } + *addr += libcaddr; + return 0; +} + +int find_libbase(pid_t pid, const char *libn, unsigned long *addr) { + struct mm mm[1000] = {0}; + unsigned long libcaddr; + int nmm; + char libc[1024] = {0}; + symtab_t s; + + if (0 > load_memmap(pid, mm, &nmm)) { + LOGD("cannot read memory map\n"); + return -1; + } + if (0 > find_libname(libn, libc, sizeof(libc), &libcaddr, mm, nmm)) { + LOGD("cannot find lib\n"); + return -1; + } + *addr = libcaddr; + return 0; +} diff --git a/app/src/main/jni/Substrate/SymbolFinder.h b/app/src/main/jni/Substrate/SymbolFinder.h new file mode 100644 index 0000000..7b99910 --- /dev/null +++ b/app/src/main/jni/Substrate/SymbolFinder.h @@ -0,0 +1,8 @@ +#ifndef SYMBOL_FINDER +#define SYMBOL_FINDER + +#include + +extern int find_name(pid_t pid, const char *name,const char *libn, unsigned long *addr); +extern int find_libbase(pid_t pid, const char *libn, unsigned long *addr); +#endif \ No newline at end of file diff --git a/app/src/main/jni/Substrate/hde64.c b/app/src/main/jni/Substrate/hde64.c new file mode 100644 index 0000000..d69f0c6 --- /dev/null +++ b/app/src/main/jni/Substrate/hde64.c @@ -0,0 +1,332 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#include +#include + +#include "hde64.h" +#include "table64.h" + +unsigned int hde64_disasm(const void *code, hde64s *hs) +{ + uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; + uint8_t op64 = 0; + + memset(hs,0,sizeof(hde64s)); + char *tmp=(char*)hs; + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((c & 0xf0) == 0x40) { + hs->flags |= F_PREFIX_REX; + if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) + op64++; + hs->rex_r = (c & 7) >> 2; + hs->rex_x = (c & 3) >> 1; + hs->rex_b = c & 1; + if (((c = *p++) & 0xf0) == 0x40) { + opcode = c; + goto error_opcode; + } + } + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + op64++; + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + error_opcode: + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde64_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde64_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde64_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde64_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde64_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if (*ht++ & pref && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + } + + if (m_mod != 3 && m_rm == 4) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (op64) { + hs->flags |= F_IMM64; + hs->imm.imm64 = *(uint64_t *)p; + p += 8; + } else if (!(pref & PRE_66)) { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else + goto imm16_ok; + } + + + if (cflags & C_IMM16) { + imm16_ok: + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} diff --git a/app/src/main/jni/Substrate/hde64.h b/app/src/main/jni/Substrate/hde64.h new file mode 100644 index 0000000..2fcc4cb --- /dev/null +++ b/app/src/main/jni/Substrate/hde64.h @@ -0,0 +1,112 @@ +/* + * Hacker Disassembler Engine 64 + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde64.h: C/C++ header file + * + */ + +#ifndef _HDE64_H_ +#define _HDE64_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_IMM64 0x00000020 +#define F_DISP8 0x00000040 +#define F_DISP16 0x00000080 +#define F_DISP32 0x00000100 +#define F_RELATIVE 0x00000200 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_REX 0x40000000 +#define F_PREFIX_ANY 0x7f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t rex; + uint8_t rex_w; + uint8_t rex_r; + uint8_t rex_x; + uint8_t rex_b; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + uint64_t imm64; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde64s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde64_disasm(const void *code, hde64s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE64_H_ */ diff --git a/app/src/main/jni/Substrate/table64.h b/app/src/main/jni/Substrate/table64.h new file mode 100644 index 0000000..144f290 --- /dev/null +++ b/app/src/main/jni/Substrate/table64.h @@ -0,0 +1,74 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xfd +#define DELTA_FPU_MODRM 0x104 +#define DELTA_PREFIXES 0x13c +#define DELTA_OP_LOCK_OK 0x1ae +#define DELTA_OP2_LOCK_OK 0x1c6 +#define DELTA_OP_ONLY_MEM 0x1d8 +#define DELTA_OP2_ONLY_MEM 0x1e7 + +unsigned char hde64_table[] = { + 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, + 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, + 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, + 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, + 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, + 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, + 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, + 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, + 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, + 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, + 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, + 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, + 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, + 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, + 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, + 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, + 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, + 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, + 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, + 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, + 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, + 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, + 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, + 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, + 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, + 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, + 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, + 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, + 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, + 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, + 0x00,0xf0,0x02,0x00 +}; diff --git a/app/src/main/jni/main.cpp b/app/src/main/jni/main.cpp new file mode 100644 index 0000000..9108633 --- /dev/null +++ b/app/src/main/jni/main.cpp @@ -0,0 +1,182 @@ +#pragma once +#include +#include "AlguiLog.h" +#include "AlguiMemTool.h" +#include "AlguiMemTool_jni.h" +#include "Hook.h" +#include "ByNameModding/Tools.h" +#include "ByNameModding/fake_dlfcn.h" +#include "ByNameModding/Il2Cpp.h" +//作者:ByteCat 作者QQ:3353484607 游戏逆向交流QQ群:931212209 +#if defined(__arm__) && !defined(__aarch64__) //针对 ARM 32 位架构 +#define ABI "ARM32" +#elif defined(__aarch64__) //针对 ARM 64 位架构 +#define ABI "ARM64" +#elif defined(__x86_64__) || defined(_M_X64) //针对 x64 架构 +#define ABI "x64" +#elif defined(__i386__) || defined(_M_IX86) //针对 x86 架构 +#define ABI "x86" +#else //其他架构或未知架构 +#define ABI "null" +#endif + +std::map Fields; +std::map Methods; +uintptr_t g_il2cpp; + +extern "C" { + + //HOOK示例 修改血量 + //确保方法签名与游戏原生方法签名保持一致 + bool isModHP = false;//控制开关 + bool isAutoUpdateHP = false;//控制开关 + void (*nativeMethod)(void* t,int InItemID, int Count);//存储游戏原生方法 + void newMethod(void* t,int InItemID, int Count) {//我们替换后的新方法 + //通过开关控制修改 只有开启时我们才改变变量数据 + if(isModHP) + //如果需要修改方法所在类的变量 + //可以通过方法隐式传入的this指针进行偏移 间接获取到该变量 + + //记得执行游戏原生方法以免干扰游戏逻辑 + nativeMethod(t,InItemID,Count); + //如果方法是有返回值的 那么我们拦截返回自己需要的数据 + //return 999; + } + /*修改函数返回值*/ + int (*old_Health)(void *instance); +int Health (void *instance) { + if (instance != NULL) { + return 999;//返回值也就是修改值 + // return (int) 变量名; + } + return old_Health(instance); +} + + + //启动时在此线程进行HOOK + void *hook_thread(void *) { + do { + sleep(1);//等待需要HOOK的库加载完成再进行HOOK + } while (!isLibraryLoaded("libil2cpp.so")); + /*这里就是自动更新的方法名了*/ + if(isAutoUpdateHP){ + Methods["血量"] = (uintptr_t) Il2CppGetMethodOffset("Assembly-CSharp.dll", "", "PlayerStats", "get_maxHealth",0); + } + //通过偏移量对函数HOOK + HOOK("libil2cpp.so", "0x6a34e74",newMethod, nativeMethod); + //通过符号对函数HOOK + /*自动获取偏移量hook*/ +Tools::Hook((void *) Methods["血量"], (void *) Health, (void **) &old_Health); + return NULL; + } + + //从Java控制jni HOOK的方法(不支持root) 参数:功能ID,该功能开关状态,修改值(可选 对于在拖动条或输入框自定义修改值) + //Java层方法签名:public static native void JniHook(int id,boolean isSwitch,double value); + JNIEXPORT void JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_JniHook(JNIEnv* env, jclass cls,jint id,jboolean isSwitch,jdouble value) + { + //id=Java传入的功能ID + //isSwitch=Java传入的开关 + //value=Java传入的值(对于需要使用拖动条或输入框自定义修改) + + //自己定义对应Hook功能的ID 比如下面0代表修改HP + switch(id){ + case 0: + isModHP=isSwitch;//设置开关 + break; + case 1: + + isAutoUpdateHP=isSwitch;//设置开关 + break; + //... + } + } + + //从Java控制jni内存外挂功能的方法 参数:功能ID,该功能开关状态,修改值(可选 对于在拖动条或输入框自定义修改值) + //Java层方法签名:public static native void JniSwitch(int id,boolean isSwitch,String value); + JNIEXPORT void JNICALL Java_com_bytecat_algui_AlguiHacker_AlguiNativeMemTool_JniSwitch(JNIEnv* env, jclass cls,jint id,jboolean isSwitch,jstring jvalue) + { + const char* value = env->GetStringUTFChars(jvalue, 0); + + //id=Java传入的功能ID + //isSwitch=Java传入的开关 + //value=Java传入的值(对于需要使用拖动条或输入框自定义修改) + + //自己定义对应功能的ID 比如下面0代表飞天功能 + switch(id){ + case 0: + if(isSwitch){ + //开启飞天 + clearResultList();//清空之前的搜索结果 + setPackageName("com.fingersoft.hillclimb.noncmcc");//设置包名 + setMemoryArea(RANGE_ANONYMOUS);//设置内存 + MemorySearch("120", TYPE_DWORD);//内存搜索 【主特征码 支持范围,联合】 + ImproveOffset("1", TYPE_DWORD, -8);//偏移筛选特征码 【副特征码1 支持范围,联合】 + ImproveOffset("12", TYPE_DWORD, -4);//偏移筛选特征码 【副特征码2】 + //n个副特征码... + MemoryOffsetWrite("999999", TYPE_DWORD, 1, false,false);//筛选结果偏移修改 【如果需要冻结将false改为true】,需要保护就把第二个改true + //对于自定义修改 + //MemoryOffsetWrite(value, TYPE_DWORD, 1, false);//筛选结果偏移修改 【如果需要冻结将false改为true】 + clearResultList();//修改完成 则清空这次的搜索结果 + }else{ + //关闭飞天 + clearResultList();//清空之前的搜索结果 + setPackageName("com.fingersoft.hillclimb.noncmcc");//设置包名 + setMemoryArea(RANGE_ANONYMOUS);//设置内存 + MemorySearch("120", TYPE_DWORD);//内存搜索 【主特征码 支持范围,联合】 + ImproveOffset("1", TYPE_DWORD, -8);//偏移筛选特征码 【副特征码1 支持范围,联合】 + ImproveOffset("12", TYPE_DWORD, -4);//偏移筛选特征码 【副特征码2】 + //n个副特征码... + MemoryOffsetWrite("999999", TYPE_DWORD, 1, false,false);//筛选结果偏移修改 【如果需要冻结将false改为true】,需要保护就把第二个改true + clearResultList();//修改完成 则清空这次的搜索结果 + + } + break; + case 1: + if(isSwitch){ + //开启 + }else{ + //关闭 + } + break; + //... + } + env->ReleaseStringUTFChars(jvalue, value); + } + /* + //内存修改示例 + void __example__() { + //动态基址内存修改示例 + setPackageName("com.yodo1.SkiSafari.yodo1");//设置包名 + unsigned long sAddr = getModuleBaseAddr("libil2cpp.so:bss", HEAD_CB);//获取模块基址 【模块名内使用[1]来代表获取第几个模块的基址 xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + unsigned long daddr = jump64(jump64(jump64(sAddr + 0x88B8) + 0xA0) + 0x118) + 0x18;//跳转指针 跳到目标地址 【32位使用 jump32 64位使用jump64】 + //跳转指针如果不直观请使用下面这种方式 + /*unsigned long p1 = jumpPointer64(sAddr + 0x88B8); + unsigned long p2 = jumpPointer64(p1 + 0xA0); + unsigned long p3 = jumpPointer64(p2 + 0x118); + unsigned long addr = p3 + 0x18; + setMemoryAddrValue("999999", daddr, TYPE_DWORD, false);//修改目标值 【如果需要冻结将false改为true】 + + //静态基址内存修改示例 + setPackageName("com.fingersoft.hillclimb.noncmcc");//设置包名 + unsigned long jaddr = getModuleBaseAddr("libgame.so", HEAD_XA) + 0x376E10; //从模块基址偏移获取目标地址 【模块名内使用[1]来代表获取第几个模块的基址 xa模块传HEAD_XA cb模块传HEAD_CB cd模块传HEAD_CD】 + setMemoryAddrValue("999999", jaddr, TYPE_DWORD, false);//修改目标值 【如果需要冻结将false改为true】 + +*/ + + + //初始化Jni + JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { + return -1; + } + + LOGI("Algui动态共享库", "当前在 %s 运行",ABI); + //创建HOOK线程,对于无需HOOK请注释避免影响性能 + pthread_t ptid; + pthread_create(&ptid, NULL, hook_thread, NULL); + return JNI_VERSION_1_6; + } + + +} diff --git a/app/src/main/jniLibs/arm64-v8a/libAlgui.so b/app/src/main/jniLibs/arm64-v8a/libAlgui.so new file mode 100644 index 0000000..1f9180b Binary files /dev/null and b/app/src/main/jniLibs/arm64-v8a/libAlgui.so differ diff --git a/app/src/main/jniLibs/armeabi-v7a/libAlgui.so b/app/src/main/jniLibs/armeabi-v7a/libAlgui.so new file mode 100644 index 0000000..93beb74 Binary files /dev/null and b/app/src/main/jniLibs/armeabi-v7a/libAlgui.so differ diff --git a/app/src/main/jniLibs/x86/libAlgui.so b/app/src/main/jniLibs/x86/libAlgui.so new file mode 100644 index 0000000..a64bdd5 Binary files /dev/null and b/app/src/main/jniLibs/x86/libAlgui.so differ diff --git a/app/src/main/jniLibs/x86_64/libAlgui.so b/app/src/main/jniLibs/x86_64/libAlgui.so new file mode 100644 index 0000000..4a9647e Binary files /dev/null and b/app/src/main/jniLibs/x86_64/libAlgui.so differ diff --git a/app/src/main/obj/local/arm64-v8a/libAlgui.so b/app/src/main/obj/local/arm64-v8a/libAlgui.so new file mode 100644 index 0000000..fc364ba Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/libAlgui.so differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/And64InlineHook/And64InlineHook.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/And64InlineHook/And64InlineHook.o new file mode 100644 index 0000000..7e7efcc Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/And64InlineHook/And64InlineHook.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/And64InlineHook/And64InlineHook.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/And64InlineHook/And64InlineHook.o.d new file mode 100644 index 0000000..056a45d --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/And64InlineHook/And64InlineHook.o.d @@ -0,0 +1,4 @@ +src/main/obj/local/arm64-v8a/objs/Algui/And64InlineHook/And64InlineHook.o: \ + src/main/jni/And64InlineHook/And64InlineHook.cpp \ + src/main/jni/And64InlineHook/And64InlineHook.hpp +src/main/jni/And64InlineHook/And64InlineHook.hpp: diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Il2Cpp.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Il2Cpp.o new file mode 100644 index 0000000..8444d2a Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Il2Cpp.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Il2Cpp.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Il2Cpp.o.d new file mode 100644 index 0000000..4f59fcb --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Il2Cpp.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Il2Cpp.o: \ + src/main/jni/ByNameModding/Il2Cpp.cpp \ + src/main/jni/ByNameModding/Il2Cpp.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/ByNameModding/fake_dlfcn.h +src/main/jni/ByNameModding/Il2Cpp.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/ByNameModding/fake_dlfcn.h: diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Tools.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Tools.o new file mode 100644 index 0000000..81a9873 Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Tools.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Tools.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Tools.o.d new file mode 100644 index 0000000..1e42f99 --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Tools.o.d @@ -0,0 +1,10 @@ +src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/Tools.o: \ + src/main/jni/ByNameModding/Tools.cpp \ + src/main/jni/ByNameModding/Tools.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/CydiaSubstrate.h +src/main/jni/ByNameModding/Tools.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/CydiaSubstrate.h: diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/fake_dlfcn.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/fake_dlfcn.o new file mode 100644 index 0000000..d57e835 Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/fake_dlfcn.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/fake_dlfcn.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/fake_dlfcn.o.d new file mode 100644 index 0000000..eb7086c --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/fake_dlfcn.o.d @@ -0,0 +1,2 @@ +src/main/obj/local/arm64-v8a/objs/Algui/ByNameModding/fake_dlfcn.o: \ + src/main/jni/ByNameModding/fake_dlfcn.cpp diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateDebug.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateDebug.o new file mode 100644 index 0000000..1b211a9 Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateDebug.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateDebug.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateDebug.o.d new file mode 100644 index 0000000..e817f3e --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateDebug.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateDebug.o: \ + src/main/jni/Substrate/SubstrateDebug.cpp \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/SubstrateDebug.hpp \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/SubstrateDebug.hpp: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateHook.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateHook.o new file mode 100644 index 0000000..f26fd87 Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateHook.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateHook.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateHook.o.d new file mode 100644 index 0000000..099f884 --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateHook.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstrateHook.o: \ + src/main/jni/Substrate/SubstrateHook.cpp \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/Substrate/SubstrateDebug.hpp \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/Substrate/SubstrateDebug.hpp: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstratePosixMemory.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstratePosixMemory.o new file mode 100644 index 0000000..215de83 Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstratePosixMemory.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstratePosixMemory.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstratePosixMemory.o.d new file mode 100644 index 0000000..f7e8a3d --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstratePosixMemory.o.d @@ -0,0 +1,6 @@ +src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SubstratePosixMemory.o: \ + src/main/jni/Substrate/SubstratePosixMemory.cpp \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SymbolFinder.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SymbolFinder.o new file mode 100644 index 0000000..0991390 Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SymbolFinder.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SymbolFinder.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SymbolFinder.o.d new file mode 100644 index 0000000..1e3b4e8 --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SymbolFinder.o.d @@ -0,0 +1,4 @@ +src/main/obj/local/arm64-v8a/objs/Algui/Substrate/SymbolFinder.o: \ + src/main/jni/Substrate/SymbolFinder.cpp \ + src/main/jni/Substrate/SymbolFinder.h +src/main/jni/Substrate/SymbolFinder.h: diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/hde64.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/hde64.o new file mode 100644 index 0000000..45c129d Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/hde64.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/hde64.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/hde64.o.d new file mode 100644 index 0000000..f739c97 --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/Substrate/hde64.o.d @@ -0,0 +1,5 @@ +src/main/obj/local/arm64-v8a/objs/Algui/Substrate/hde64.o: \ + src/main/jni/Substrate/hde64.c src/main/jni/Substrate/hde64.h \ + src/main/jni/Substrate/table64.h +src/main/jni/Substrate/hde64.h: +src/main/jni/Substrate/table64.h: diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/main.o b/app/src/main/obj/local/arm64-v8a/objs/Algui/main.o new file mode 100644 index 0000000..684dc88 Binary files /dev/null and b/app/src/main/obj/local/arm64-v8a/objs/Algui/main.o differ diff --git a/app/src/main/obj/local/arm64-v8a/objs/Algui/main.o.d b/app/src/main/obj/local/arm64-v8a/objs/Algui/main.o.d new file mode 100644 index 0000000..302629a --- /dev/null +++ b/app/src/main/obj/local/arm64-v8a/objs/Algui/main.o.d @@ -0,0 +1,21 @@ +src/main/obj/local/arm64-v8a/objs/Algui/main.o: src/main/jni/main.cpp \ + src/main/jni/AlguiLog.h src/main/jni/AlguiMemTool.h \ + src/main/jni/AlguiMemTool_jni.h src/main/jni/Hook.h \ + src/main/jni/And64InlineHook/And64InlineHook.hpp \ + src/main/jni/ByNameModding/Tools.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/ByNameModding/fake_dlfcn.h \ + src/main/jni/ByNameModding/Il2Cpp.h +src/main/jni/AlguiLog.h: +src/main/jni/AlguiMemTool.h: +src/main/jni/AlguiMemTool_jni.h: +src/main/jni/Hook.h: +src/main/jni/And64InlineHook/And64InlineHook.hpp: +src/main/jni/ByNameModding/Tools.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/ByNameModding/fake_dlfcn.h: +src/main/jni/ByNameModding/Il2Cpp.h: diff --git a/app/src/main/obj/local/armeabi-v7a/libAlgui.so b/app/src/main/obj/local/armeabi-v7a/libAlgui.so new file mode 100644 index 0000000..cb8c49c Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/libAlgui.so differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/And64InlineHook/And64InlineHook.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/And64InlineHook/And64InlineHook.o new file mode 100644 index 0000000..934289a Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/And64InlineHook/And64InlineHook.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/And64InlineHook/And64InlineHook.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/And64InlineHook/And64InlineHook.o.d new file mode 100644 index 0000000..9b177db --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/And64InlineHook/And64InlineHook.o.d @@ -0,0 +1,2 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/And64InlineHook/And64InlineHook.o: \ + src/main/jni/And64InlineHook/And64InlineHook.cpp diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Il2Cpp.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Il2Cpp.o new file mode 100644 index 0000000..c321e19 Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Il2Cpp.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Il2Cpp.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Il2Cpp.o.d new file mode 100644 index 0000000..01b2e02 --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Il2Cpp.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Il2Cpp.o: \ + src/main/jni/ByNameModding/Il2Cpp.cpp \ + src/main/jni/ByNameModding/Il2Cpp.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/ByNameModding/fake_dlfcn.h +src/main/jni/ByNameModding/Il2Cpp.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/ByNameModding/fake_dlfcn.h: diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Tools.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Tools.o new file mode 100644 index 0000000..c5f1f8a Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Tools.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Tools.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Tools.o.d new file mode 100644 index 0000000..754a50d --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Tools.o.d @@ -0,0 +1,10 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/Tools.o: \ + src/main/jni/ByNameModding/Tools.cpp \ + src/main/jni/ByNameModding/Tools.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/CydiaSubstrate.h +src/main/jni/ByNameModding/Tools.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/CydiaSubstrate.h: diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/fake_dlfcn.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/fake_dlfcn.o new file mode 100644 index 0000000..3af0652 Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/fake_dlfcn.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/fake_dlfcn.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/fake_dlfcn.o.d new file mode 100644 index 0000000..fca8dbe --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/fake_dlfcn.o.d @@ -0,0 +1,2 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/ByNameModding/fake_dlfcn.o: \ + src/main/jni/ByNameModding/fake_dlfcn.cpp diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateDebug.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateDebug.o new file mode 100644 index 0000000..076d481 Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateDebug.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateDebug.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateDebug.o.d new file mode 100644 index 0000000..8287a8e --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateDebug.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateDebug.o: \ + src/main/jni/Substrate/SubstrateDebug.cpp \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/SubstrateDebug.hpp \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/SubstrateDebug.hpp: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateHook.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateHook.o new file mode 100644 index 0000000..d707a74 Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateHook.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateHook.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateHook.o.d new file mode 100644 index 0000000..3b572ad --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateHook.o.d @@ -0,0 +1,10 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstrateHook.o: \ + src/main/jni/Substrate/SubstrateHook.cpp \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/Substrate/SubstrateDebug.hpp \ + src/main/jni/Substrate/SubstrateLog.hpp \ + src/main/jni/Substrate/SubstrateARM.hpp +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/Substrate/SubstrateDebug.hpp: +src/main/jni/Substrate/SubstrateLog.hpp: +src/main/jni/Substrate/SubstrateARM.hpp: diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstratePosixMemory.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstratePosixMemory.o new file mode 100644 index 0000000..90c0bf1 Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstratePosixMemory.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstratePosixMemory.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstratePosixMemory.o.d new file mode 100644 index 0000000..d5174d7 --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstratePosixMemory.o.d @@ -0,0 +1,6 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SubstratePosixMemory.o: \ + src/main/jni/Substrate/SubstratePosixMemory.cpp \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SymbolFinder.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SymbolFinder.o new file mode 100644 index 0000000..657cbd5 Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SymbolFinder.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SymbolFinder.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SymbolFinder.o.d new file mode 100644 index 0000000..800563d --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SymbolFinder.o.d @@ -0,0 +1,4 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/SymbolFinder.o: \ + src/main/jni/Substrate/SymbolFinder.cpp \ + src/main/jni/Substrate/SymbolFinder.h +src/main/jni/Substrate/SymbolFinder.h: diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/hde64.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/hde64.o new file mode 100644 index 0000000..58b0b89 Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/hde64.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/hde64.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/hde64.o.d new file mode 100644 index 0000000..2a38012 --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/hde64.o.d @@ -0,0 +1,5 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/Substrate/hde64.o: \ + src/main/jni/Substrate/hde64.c src/main/jni/Substrate/hde64.h \ + src/main/jni/Substrate/table64.h +src/main/jni/Substrate/hde64.h: +src/main/jni/Substrate/table64.h: diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/main.o b/app/src/main/obj/local/armeabi-v7a/objs/Algui/main.o new file mode 100644 index 0000000..486b334 Binary files /dev/null and b/app/src/main/obj/local/armeabi-v7a/objs/Algui/main.o differ diff --git a/app/src/main/obj/local/armeabi-v7a/objs/Algui/main.o.d b/app/src/main/obj/local/armeabi-v7a/objs/Algui/main.o.d new file mode 100644 index 0000000..2f6547c --- /dev/null +++ b/app/src/main/obj/local/armeabi-v7a/objs/Algui/main.o.d @@ -0,0 +1,19 @@ +src/main/obj/local/armeabi-v7a/objs/Algui/main.o: src/main/jni/main.cpp \ + src/main/jni/AlguiLog.h src/main/jni/AlguiMemTool.h \ + src/main/jni/AlguiMemTool_jni.h src/main/jni/Hook.h \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/ByNameModding/Tools.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/ByNameModding/fake_dlfcn.h \ + src/main/jni/ByNameModding/Il2Cpp.h +src/main/jni/AlguiLog.h: +src/main/jni/AlguiMemTool.h: +src/main/jni/AlguiMemTool_jni.h: +src/main/jni/Hook.h: +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/ByNameModding/Tools.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/ByNameModding/fake_dlfcn.h: +src/main/jni/ByNameModding/Il2Cpp.h: diff --git a/app/src/main/obj/local/x86/libAlgui.so b/app/src/main/obj/local/x86/libAlgui.so new file mode 100644 index 0000000..f0969e0 Binary files /dev/null and b/app/src/main/obj/local/x86/libAlgui.so differ diff --git a/app/src/main/obj/local/x86/objs/Algui/And64InlineHook/And64InlineHook.o b/app/src/main/obj/local/x86/objs/Algui/And64InlineHook/And64InlineHook.o new file mode 100644 index 0000000..805522e Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/And64InlineHook/And64InlineHook.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/And64InlineHook/And64InlineHook.o.d b/app/src/main/obj/local/x86/objs/Algui/And64InlineHook/And64InlineHook.o.d new file mode 100644 index 0000000..6bb3dec --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/And64InlineHook/And64InlineHook.o.d @@ -0,0 +1,2 @@ +src/main/obj/local/x86/objs/Algui/And64InlineHook/And64InlineHook.o: \ + src/main/jni/And64InlineHook/And64InlineHook.cpp diff --git a/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Il2Cpp.o b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Il2Cpp.o new file mode 100644 index 0000000..76eeac3 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Il2Cpp.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Il2Cpp.o.d b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Il2Cpp.o.d new file mode 100644 index 0000000..850089c --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Il2Cpp.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/x86/objs/Algui/ByNameModding/Il2Cpp.o: \ + src/main/jni/ByNameModding/Il2Cpp.cpp \ + src/main/jni/ByNameModding/Il2Cpp.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/ByNameModding/fake_dlfcn.h +src/main/jni/ByNameModding/Il2Cpp.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/ByNameModding/fake_dlfcn.h: diff --git a/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Tools.o b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Tools.o new file mode 100644 index 0000000..9677731 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Tools.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Tools.o.d b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Tools.o.d new file mode 100644 index 0000000..cfbf545 --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/Tools.o.d @@ -0,0 +1,10 @@ +src/main/obj/local/x86/objs/Algui/ByNameModding/Tools.o: \ + src/main/jni/ByNameModding/Tools.cpp \ + src/main/jni/ByNameModding/Tools.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/CydiaSubstrate.h +src/main/jni/ByNameModding/Tools.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/CydiaSubstrate.h: diff --git a/app/src/main/obj/local/x86/objs/Algui/ByNameModding/fake_dlfcn.o b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/fake_dlfcn.o new file mode 100644 index 0000000..e41c830 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/fake_dlfcn.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/ByNameModding/fake_dlfcn.o.d b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/fake_dlfcn.o.d new file mode 100644 index 0000000..49e6f1e --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/ByNameModding/fake_dlfcn.o.d @@ -0,0 +1,2 @@ +src/main/obj/local/x86/objs/Algui/ByNameModding/fake_dlfcn.o: \ + src/main/jni/ByNameModding/fake_dlfcn.cpp diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateDebug.o b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateDebug.o new file mode 100644 index 0000000..113e6f0 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateDebug.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateDebug.o.d b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateDebug.o.d new file mode 100644 index 0000000..998fa35 --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateDebug.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/x86/objs/Algui/Substrate/SubstrateDebug.o: \ + src/main/jni/Substrate/SubstrateDebug.cpp \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/SubstrateDebug.hpp \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/SubstrateDebug.hpp: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateHook.o b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateHook.o new file mode 100644 index 0000000..e23e975 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateHook.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateHook.o.d b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateHook.o.d new file mode 100644 index 0000000..06875fb --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstrateHook.o.d @@ -0,0 +1,13 @@ +src/main/obj/local/x86/objs/Algui/Substrate/SubstrateHook.o: \ + src/main/jni/Substrate/SubstrateHook.cpp \ + src/main/jni/Substrate/CydiaSubstrate.h src/main/jni/Substrate/hde64.h \ + src/main/jni/Substrate/SubstrateDebug.hpp \ + src/main/jni/Substrate/SubstrateLog.hpp \ + src/main/jni/Substrate/SubstrateX86.hpp \ + src/main/jni/Substrate/Buffer.hpp +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/Substrate/hde64.h: +src/main/jni/Substrate/SubstrateDebug.hpp: +src/main/jni/Substrate/SubstrateLog.hpp: +src/main/jni/Substrate/SubstrateX86.hpp: +src/main/jni/Substrate/Buffer.hpp: diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstratePosixMemory.o b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstratePosixMemory.o new file mode 100644 index 0000000..fe350d6 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstratePosixMemory.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstratePosixMemory.o.d b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstratePosixMemory.o.d new file mode 100644 index 0000000..1fae90a --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/Substrate/SubstratePosixMemory.o.d @@ -0,0 +1,6 @@ +src/main/obj/local/x86/objs/Algui/Substrate/SubstratePosixMemory.o: \ + src/main/jni/Substrate/SubstratePosixMemory.cpp \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/SymbolFinder.o b/app/src/main/obj/local/x86/objs/Algui/Substrate/SymbolFinder.o new file mode 100644 index 0000000..71a9950 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/Substrate/SymbolFinder.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/SymbolFinder.o.d b/app/src/main/obj/local/x86/objs/Algui/Substrate/SymbolFinder.o.d new file mode 100644 index 0000000..557a680 --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/Substrate/SymbolFinder.o.d @@ -0,0 +1,4 @@ +src/main/obj/local/x86/objs/Algui/Substrate/SymbolFinder.o: \ + src/main/jni/Substrate/SymbolFinder.cpp \ + src/main/jni/Substrate/SymbolFinder.h +src/main/jni/Substrate/SymbolFinder.h: diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/hde64.o b/app/src/main/obj/local/x86/objs/Algui/Substrate/hde64.o new file mode 100644 index 0000000..3dfeb44 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/Substrate/hde64.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/Substrate/hde64.o.d b/app/src/main/obj/local/x86/objs/Algui/Substrate/hde64.o.d new file mode 100644 index 0000000..68efbdd --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/Substrate/hde64.o.d @@ -0,0 +1,5 @@ +src/main/obj/local/x86/objs/Algui/Substrate/hde64.o: \ + src/main/jni/Substrate/hde64.c src/main/jni/Substrate/hde64.h \ + src/main/jni/Substrate/table64.h +src/main/jni/Substrate/hde64.h: +src/main/jni/Substrate/table64.h: diff --git a/app/src/main/obj/local/x86/objs/Algui/main.o b/app/src/main/obj/local/x86/objs/Algui/main.o new file mode 100644 index 0000000..7057fb0 Binary files /dev/null and b/app/src/main/obj/local/x86/objs/Algui/main.o differ diff --git a/app/src/main/obj/local/x86/objs/Algui/main.o.d b/app/src/main/obj/local/x86/objs/Algui/main.o.d new file mode 100644 index 0000000..27cc700 --- /dev/null +++ b/app/src/main/obj/local/x86/objs/Algui/main.o.d @@ -0,0 +1,19 @@ +src/main/obj/local/x86/objs/Algui/main.o: src/main/jni/main.cpp \ + src/main/jni/AlguiLog.h src/main/jni/AlguiMemTool.h \ + src/main/jni/AlguiMemTool_jni.h src/main/jni/Hook.h \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/ByNameModding/Tools.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/ByNameModding/fake_dlfcn.h \ + src/main/jni/ByNameModding/Il2Cpp.h +src/main/jni/AlguiLog.h: +src/main/jni/AlguiMemTool.h: +src/main/jni/AlguiMemTool_jni.h: +src/main/jni/Hook.h: +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/ByNameModding/Tools.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/ByNameModding/fake_dlfcn.h: +src/main/jni/ByNameModding/Il2Cpp.h: diff --git a/app/src/main/obj/local/x86_64/libAlgui.so b/app/src/main/obj/local/x86_64/libAlgui.so new file mode 100644 index 0000000..b3f4129 Binary files /dev/null and b/app/src/main/obj/local/x86_64/libAlgui.so differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/And64InlineHook/And64InlineHook.o b/app/src/main/obj/local/x86_64/objs/Algui/And64InlineHook/And64InlineHook.o new file mode 100644 index 0000000..7640af0 Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/And64InlineHook/And64InlineHook.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/And64InlineHook/And64InlineHook.o.d b/app/src/main/obj/local/x86_64/objs/Algui/And64InlineHook/And64InlineHook.o.d new file mode 100644 index 0000000..b844e53 --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/And64InlineHook/And64InlineHook.o.d @@ -0,0 +1,2 @@ +src/main/obj/local/x86_64/objs/Algui/And64InlineHook/And64InlineHook.o: \ + src/main/jni/And64InlineHook/And64InlineHook.cpp diff --git a/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Il2Cpp.o b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Il2Cpp.o new file mode 100644 index 0000000..e60bc22 Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Il2Cpp.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Il2Cpp.o.d b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Il2Cpp.o.d new file mode 100644 index 0000000..d8a1662 --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Il2Cpp.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/x86_64/objs/Algui/ByNameModding/Il2Cpp.o: \ + src/main/jni/ByNameModding/Il2Cpp.cpp \ + src/main/jni/ByNameModding/Il2Cpp.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/ByNameModding/fake_dlfcn.h +src/main/jni/ByNameModding/Il2Cpp.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/ByNameModding/fake_dlfcn.h: diff --git a/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Tools.o b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Tools.o new file mode 100644 index 0000000..00d3cfc Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Tools.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Tools.o.d b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Tools.o.d new file mode 100644 index 0000000..e858510 --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/Tools.o.d @@ -0,0 +1,10 @@ +src/main/obj/local/x86_64/objs/Algui/ByNameModding/Tools.o: \ + src/main/jni/ByNameModding/Tools.cpp \ + src/main/jni/ByNameModding/Tools.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/CydiaSubstrate.h +src/main/jni/ByNameModding/Tools.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/CydiaSubstrate.h: diff --git a/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/fake_dlfcn.o b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/fake_dlfcn.o new file mode 100644 index 0000000..8afb199 Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/fake_dlfcn.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/fake_dlfcn.o.d b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/fake_dlfcn.o.d new file mode 100644 index 0000000..ceec585 --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/ByNameModding/fake_dlfcn.o.d @@ -0,0 +1,2 @@ +src/main/obj/local/x86_64/objs/Algui/ByNameModding/fake_dlfcn.o: \ + src/main/jni/ByNameModding/fake_dlfcn.cpp diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateDebug.o b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateDebug.o new file mode 100644 index 0000000..8752beb Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateDebug.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateDebug.o.d b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateDebug.o.d new file mode 100644 index 0000000..8102dd9 --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateDebug.o.d @@ -0,0 +1,8 @@ +src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateDebug.o: \ + src/main/jni/Substrate/SubstrateDebug.cpp \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/SubstrateDebug.hpp \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/SubstrateDebug.hpp: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateHook.o b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateHook.o new file mode 100644 index 0000000..caeb931 Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateHook.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateHook.o.d b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateHook.o.d new file mode 100644 index 0000000..7deffb8 --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateHook.o.d @@ -0,0 +1,13 @@ +src/main/obj/local/x86_64/objs/Algui/Substrate/SubstrateHook.o: \ + src/main/jni/Substrate/SubstrateHook.cpp \ + src/main/jni/Substrate/CydiaSubstrate.h src/main/jni/Substrate/hde64.h \ + src/main/jni/Substrate/SubstrateDebug.hpp \ + src/main/jni/Substrate/SubstrateLog.hpp \ + src/main/jni/Substrate/SubstrateX86.hpp \ + src/main/jni/Substrate/Buffer.hpp +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/Substrate/hde64.h: +src/main/jni/Substrate/SubstrateDebug.hpp: +src/main/jni/Substrate/SubstrateLog.hpp: +src/main/jni/Substrate/SubstrateX86.hpp: +src/main/jni/Substrate/Buffer.hpp: diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstratePosixMemory.o b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstratePosixMemory.o new file mode 100644 index 0000000..8dbfb82 Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstratePosixMemory.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstratePosixMemory.o.d b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstratePosixMemory.o.d new file mode 100644 index 0000000..a6917cb --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SubstratePosixMemory.o.d @@ -0,0 +1,6 @@ +src/main/obj/local/x86_64/objs/Algui/Substrate/SubstratePosixMemory.o: \ + src/main/jni/Substrate/SubstratePosixMemory.cpp \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/Substrate/SubstrateLog.hpp +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/Substrate/SubstrateLog.hpp: diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SymbolFinder.o b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SymbolFinder.o new file mode 100644 index 0000000..4c68436 Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SymbolFinder.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SymbolFinder.o.d b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SymbolFinder.o.d new file mode 100644 index 0000000..08cdc36 --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/SymbolFinder.o.d @@ -0,0 +1,4 @@ +src/main/obj/local/x86_64/objs/Algui/Substrate/SymbolFinder.o: \ + src/main/jni/Substrate/SymbolFinder.cpp \ + src/main/jni/Substrate/SymbolFinder.h +src/main/jni/Substrate/SymbolFinder.h: diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/hde64.o b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/hde64.o new file mode 100644 index 0000000..76d94fb Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/hde64.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/Substrate/hde64.o.d b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/hde64.o.d new file mode 100644 index 0000000..d2f12c1 --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/Substrate/hde64.o.d @@ -0,0 +1,5 @@ +src/main/obj/local/x86_64/objs/Algui/Substrate/hde64.o: \ + src/main/jni/Substrate/hde64.c src/main/jni/Substrate/hde64.h \ + src/main/jni/Substrate/table64.h +src/main/jni/Substrate/hde64.h: +src/main/jni/Substrate/table64.h: diff --git a/app/src/main/obj/local/x86_64/objs/Algui/main.o b/app/src/main/obj/local/x86_64/objs/Algui/main.o new file mode 100644 index 0000000..67d14a5 Binary files /dev/null and b/app/src/main/obj/local/x86_64/objs/Algui/main.o differ diff --git a/app/src/main/obj/local/x86_64/objs/Algui/main.o.d b/app/src/main/obj/local/x86_64/objs/Algui/main.o.d new file mode 100644 index 0000000..e3baacf --- /dev/null +++ b/app/src/main/obj/local/x86_64/objs/Algui/main.o.d @@ -0,0 +1,19 @@ +src/main/obj/local/x86_64/objs/Algui/main.o: src/main/jni/main.cpp \ + src/main/jni/AlguiLog.h src/main/jni/AlguiMemTool.h \ + src/main/jni/AlguiMemTool_jni.h src/main/jni/Hook.h \ + src/main/jni/Substrate/SubstrateHook.h \ + src/main/jni/Substrate/CydiaSubstrate.h \ + src/main/jni/ByNameModding/Tools.h \ + src/main/jni/ByNameModding/Includes.h \ + src/main/jni/ByNameModding/fake_dlfcn.h \ + src/main/jni/ByNameModding/Il2Cpp.h +src/main/jni/AlguiLog.h: +src/main/jni/AlguiMemTool.h: +src/main/jni/AlguiMemTool_jni.h: +src/main/jni/Hook.h: +src/main/jni/Substrate/SubstrateHook.h: +src/main/jni/Substrate/CydiaSubstrate.h: +src/main/jni/ByNameModding/Tools.h: +src/main/jni/ByNameModding/Includes.h: +src/main/jni/ByNameModding/fake_dlfcn.h: +src/main/jni/ByNameModding/Il2Cpp.h: diff --git a/app/src/main/res/drawable/baseline_people_alt_24.xml b/app/src/main/res/drawable/baseline_people_alt_24.xml new file mode 100644 index 0000000..5678354 --- /dev/null +++ b/app/src/main/res/drawable/baseline_people_alt_24.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher.png b/app/src/main/res/drawable/ic_launcher.png new file mode 100644 index 0000000..c58b803 Binary files /dev/null and b/app/src/main/res/drawable/ic_launcher.png differ diff --git a/app/src/main/res/drawable/ic_launcher1.png b/app/src/main/res/drawable/ic_launcher1.png new file mode 100644 index 0000000..9574ce3 Binary files /dev/null and b/app/src/main/res/drawable/ic_launcher1.png differ diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..707f814 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..cdea37b --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..7353dbd --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..7353dbd --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..b58e007 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..6b6c0b5 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..f1d6c99 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..52fadad Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..f9d6ca3 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..3a67d87 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..c916d7a Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..ead46b2 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..0ecdb00 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9ff9258 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000..8b6279d --- /dev/null +++ b/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..b29c220 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #009688 + #00796B + #FF9800 + diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..c5d5899 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..0c1cdd0 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + MIX + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..6262588 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/network_config.xml b/app/src/main/res/xml/network_config.xml new file mode 100644 index 0000000..fe8ba8e --- /dev/null +++ b/app/src/main/res/xml/network_config.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..e5fee52 --- /dev/null +++ b/build.gradle @@ -0,0 +1,41 @@ +buildscript { + ext.build_gradle_version = '7.0.2' + + repositories { + maven { url 'https://maven.aliyun.com/repository/public/' } + maven { url 'https://maven.aliyun.com/repository/google/' } + maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' } + maven { url 'https://dl.bintray.com/ppartisan/maven/' } + maven { url "https://clojars.org/repo/" } + maven { url "https://jitpack.io" } + google() + mavenLocal() + mavenCentral() + } + dependencies { + classpath "com.android.tools.build:gradle:$build_gradle_version" + + } + +} +allprojects { + repositories { + maven { url 'https://maven.aliyun.com/repository/public/' } + maven { url 'https://maven.aliyun.com/repository/google/' } + maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' } + maven { url 'https://dl.bintray.com/ppartisan/maven/' } + maven { url "https://clojars.org/repo/" } + maven { url "https://jitpack.io" } + mavenLocal() + mavenCentral() + google() + } + + + + +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/build/gen/BuildConfig.java b/build/gen/BuildConfig.java new file mode 100644 index 0000000..e6fc52e --- /dev/null +++ b/build/gen/BuildConfig.java @@ -0,0 +1,8 @@ +/** Automatically generated file. DO NOT MODIFY */ +package ; + +public final class BuildConfig { + public final static boolean DEBUG = true; + public final static String APPLICATION_ID = ""; + public final static String BUILD_TYPE = "debug"; +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..0df8b73 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,19 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=false +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=false \ No newline at end of file diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/local.properties b/local.properties new file mode 100644 index 0000000..c1cdb26 --- /dev/null +++ b/local.properties @@ -0,0 +1,10 @@ +## This file is automatically generated by Android Studio. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file should *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#sdk.dir= \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..0610ea4 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +include ':app' +rootProject.name = "AlguiV" diff --git a/更新日志.txt b/更新日志.txt new file mode 100644 index 0000000..55bfaef --- /dev/null +++ b/更新日志.txt @@ -0,0 +1,15 @@ +#1.0 +不知道 +#1.1 +不知道 +#1.2 +1:兼容低版本安卓 +2:新增设置全局文字大小方法 +#1.2.1 (20250131) +1:修复文本视图为连接时点击导致崩溃的问题 +2:修复拖动条因文本过长导致按钮大小错误的问题 +#1.2.2 (20250202) +1:修复内存保护闪退 +2.加入二次保护 +3.加入自动更新hook +4.自由选择保护或者不保护 \ No newline at end of file