mirror of
https://github.com/wechat-miniprogram/minigame-tuanjie-transform-sdk.git
synced 2026-04-21 17:25:54 +08:00
Auto-publish.
This commit is contained in:
parent
f67e7851c3
commit
d37d6d8608
@ -6,7 +6,7 @@ Removed - 删除功能/接口
|
||||
Fixed - 修复问题
|
||||
Others - 其他
|
||||
-->
|
||||
## 2026-3-15 v0.1.32 【普通更新】
|
||||
## 2026-3-16 v0.1.32 【普通更新】
|
||||
### Feature
|
||||
* 普通:更新基础库版本
|
||||
* 普通:擂台赛api新增subScoreKey参数
|
||||
|
||||
174
Editor/PCHighPerformance/PCHPBuildPreProcessor.cs
Normal file
174
Editor/PCHighPerformance/PCHPBuildPreProcessor.cs
Normal file
@ -0,0 +1,174 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEditor.SceneManagement;
|
||||
using System.IO;
|
||||
|
||||
namespace WeChatWASM
|
||||
{
|
||||
/// <summary>
|
||||
/// PC高性能小游戏构建预处理器
|
||||
/// 负责在构建前向首场景注入 WXPCHPInitScript
|
||||
/// </summary>
|
||||
public class PCHPBuildPreProcessor : IPreprocessBuildWithReport
|
||||
{
|
||||
// SDK 脚本名称常量
|
||||
private const string SDK_CLASS_NAME = "WeChatWASM.WXPCHPInitScript";
|
||||
private const string SDK_GAMEOBJECT_NAME = "WXPCHPInitScript";
|
||||
|
||||
public int callbackOrder => 0;
|
||||
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
Debug.Log("========================================");
|
||||
Debug.Log("[PC高性能小游戏] PCHPBuildPreProcessor.OnPreprocessBuild 被调用");
|
||||
Debug.Log("========================================");
|
||||
|
||||
// 只处理 Windows/Mac Standalone 构建
|
||||
var buildTarget = report.summary.platform;
|
||||
if (buildTarget != BuildTarget.StandaloneWindows64 &&
|
||||
buildTarget != BuildTarget.StandaloneOSX)
|
||||
{
|
||||
Debug.LogWarning($"[PC高性能小游戏] 当前平台 {buildTarget} 不是 Windows/Mac,跳过预处理");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[PC高性能小游戏] 开始预处理构建...");
|
||||
|
||||
try
|
||||
{
|
||||
Debug.Log("[PC高性能小游戏] → 步骤1: 检查 WXPCHPInitScript 脚本是否存在");
|
||||
EnsureSDKScriptExists();
|
||||
|
||||
Debug.Log("[PC高性能小游戏] → 步骤2: 向首场景注入 SDK GameObject");
|
||||
InjectSDKToFirstScene();
|
||||
|
||||
Debug.Log("[PC高性能小游戏] ✅ 预处理完成!");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError("========================================");
|
||||
Debug.LogError($"[PC高性能小游戏] ❌ 预处理失败: {e.Message}\n{e.StackTrace}");
|
||||
Debug.LogError("========================================");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在所有程序集中查找类型
|
||||
/// </summary>
|
||||
private System.Type FindTypeInAllAssemblies(string typeName)
|
||||
{
|
||||
foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
var type = assembly.GetType(typeName);
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确保 WXPCHPInitScript 脚本存在
|
||||
/// </summary>
|
||||
private void EnsureSDKScriptExists()
|
||||
{
|
||||
var sdkType = FindTypeInAllAssemblies(SDK_CLASS_NAME);
|
||||
if (sdkType != null)
|
||||
{
|
||||
Debug.Log($"[PC高性能小游戏] ✅ WXPCHPInitScript 脚本已加载 (程序集: {sdkType.Assembly.GetName().Name})");
|
||||
return;
|
||||
}
|
||||
|
||||
// 脚本应该在 SDK Runtime 目录,如果找不到说明 SDK 安装有问题
|
||||
Debug.LogError("[PC高性能小游戏] ❌ 找不到 WXPCHPInitScript 类型");
|
||||
Debug.LogError("[PC高性能小游戏] 请确保 WX-WASM-SDK-V2 已正确安装");
|
||||
throw new BuildFailedException("[PC高性能小游戏] 缺少 WXPCHPInitScript 脚本,请检查 SDK 安装");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向第一个启用的场景注入 SDK GameObject
|
||||
/// </summary>
|
||||
private void InjectSDKToFirstScene()
|
||||
{
|
||||
var firstScenePath = GetFirstEnabledScene();
|
||||
if (string.IsNullOrEmpty(firstScenePath))
|
||||
{
|
||||
Debug.LogWarning("[PC高性能小游戏] 没有找到启用的场景,跳过注入");
|
||||
return;
|
||||
}
|
||||
|
||||
var currentScenes = EditorSceneManager.GetSceneManagerSetup();
|
||||
var scene = EditorSceneManager.OpenScene(firstScenePath, OpenSceneMode.Single);
|
||||
|
||||
// 删除旧的对象(兼容从 EmbeddedAppletSDK 迁移)
|
||||
var oldSDK = GameObject.Find("EmbeddedAppletSDK");
|
||||
if (oldSDK != null)
|
||||
{
|
||||
Debug.Log("[PC高性能小游戏] 删除旧的 EmbeddedAppletSDK 对象");
|
||||
GameObject.DestroyImmediate(oldSDK);
|
||||
}
|
||||
|
||||
// 检查是否已存在新的 SDK 对象
|
||||
var existingSDK = GameObject.Find(SDK_GAMEOBJECT_NAME);
|
||||
if (existingSDK != null)
|
||||
{
|
||||
Debug.Log($"[PC高性能小游戏] 场景中已存在 {SDK_GAMEOBJECT_NAME},重新创建");
|
||||
GameObject.DestroyImmediate(existingSDK);
|
||||
}
|
||||
|
||||
// 创建 GameObject 并添加组件
|
||||
var sdkObject = new GameObject(SDK_GAMEOBJECT_NAME);
|
||||
var sdkType = FindTypeInAllAssemblies(SDK_CLASS_NAME);
|
||||
|
||||
if (sdkType != null)
|
||||
{
|
||||
var assemblyName = sdkType.Assembly.GetName().Name;
|
||||
Debug.Log($"[PC高性能小游戏] 找到 WXPCHPInitScript,程序集: {assemblyName}");
|
||||
|
||||
if (assemblyName.Contains("Editor"))
|
||||
{
|
||||
Debug.LogError("[PC高性能小游戏] ❌ WXPCHPInitScript 在 Editor 程序集中!");
|
||||
GameObject.DestroyImmediate(sdkObject);
|
||||
throw new BuildFailedException("[PC高性能小游戏] WXPCHPInitScript 必须在 Runtime 程序集");
|
||||
}
|
||||
|
||||
sdkObject.AddComponent(sdkType);
|
||||
Debug.Log($"[PC高性能小游戏] ✅ 已在 {scene.name} 中创建 {SDK_GAMEOBJECT_NAME} 并添加组件");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[PC高性能小游戏] ❌ 找不到 WXPCHPInitScript 类型");
|
||||
GameObject.DestroyImmediate(sdkObject);
|
||||
throw new BuildFailedException("[PC高性能小游戏] 无法找到 WXPCHPInitScript 组件");
|
||||
}
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(scene);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
RestoreScenes(currentScenes);
|
||||
}
|
||||
|
||||
private string GetFirstEnabledScene()
|
||||
{
|
||||
foreach (var scene in EditorBuildSettings.scenes)
|
||||
{
|
||||
if (scene.enabled)
|
||||
{
|
||||
return scene.path;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void RestoreScenes(UnityEditor.SceneManagement.SceneSetup[] setup)
|
||||
{
|
||||
if (setup != null && setup.Length > 0)
|
||||
{
|
||||
EditorSceneManager.RestoreSceneManagerSetup(setup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Editor/PCHighPerformance/PCHPBuildPreProcessor.cs.meta
Normal file
7
Editor/PCHighPerformance/PCHPBuildPreProcessor.cs.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2764f66c7a7ee9dfaf53ffe5f6215d0
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
110
Editor/PCHighPerformance/README_AutoInjection.md
Normal file
110
Editor/PCHighPerformance/README_AutoInjection.md
Normal file
@ -0,0 +1,110 @@
|
||||
# PC高性能小游戏 - 自动化构建注入
|
||||
|
||||
## 📂 文件结构
|
||||
|
||||
```
|
||||
WX-WASM-SDK-V2/
|
||||
├── Editor/PCHighPerformance/
|
||||
│ ├── PCHPBuildPreProcessor.cs # 构建预处理器(自动注入)
|
||||
│ ├── PCHPDebugHelper.cs # 调试工具
|
||||
│ ├── WXPCSettingHelper.cs # 构建配置助手
|
||||
│ └── WXEditorPCHPWindow.cs # 编辑器窗口
|
||||
└── Runtime/
|
||||
└── WXPCHPInitScript.cs # SDK 运行时脚本
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 功能说明
|
||||
|
||||
### 自动注入机制
|
||||
|
||||
**触发时机**:开发者点击「生成并转换」按钮,Unity 开始构建 Windows/macOS 平台前
|
||||
|
||||
**工作流程**:
|
||||
|
||||
```
|
||||
构建开始
|
||||
↓
|
||||
PCHPBuildPreProcessor.OnPreprocessBuild() 触发
|
||||
↓
|
||||
Step 1: 检查 WXPCHPInitScript 是否已加载
|
||||
├── 已加载 → 继续
|
||||
└── 未加载 → 报错中断(SDK 安装问题)
|
||||
↓
|
||||
Step 2: 打开首个启用场景
|
||||
↓
|
||||
Step 3: 检查场景是否已有 "WXPCHPInitScript" GameObject
|
||||
├── 有 → 删除重建
|
||||
└── 没有 → 创建新 GameObject + 添加 WXPCHPInitScript 组件
|
||||
↓
|
||||
Step 4: 保存场景并恢复原始布局
|
||||
↓
|
||||
继续正常构建流程
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 关键特性
|
||||
|
||||
1. **零侵入**:不修改开发者当前打开的场景
|
||||
2. **智能检测**:自动检测是否已存在脚本/对象
|
||||
3. **SDK 内置**:脚本位于 SDK Runtime 目录,无需复制到用户项目
|
||||
4. **命名空间隔离**:使用 `WeChatWASM` 命名空间避免冲突
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置说明
|
||||
|
||||
### 脚本位置
|
||||
|
||||
```
|
||||
Assets/WX-WASM-SDK-V2/Runtime/WXPCHPInitScript.cs
|
||||
```
|
||||
|
||||
**类名**:`WeChatWASM.WXPCHPInitScript`
|
||||
|
||||
**作用**:运行时初始化 PC 高性能小游戏 SDK,与宿主程序通信
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q: 为什么导出的工程没有 SDK 对象?
|
||||
|
||||
检查 Console 日志:
|
||||
- ✅ `[PC高性能小游戏] ✅ 已在 XXX 中创建 WXPCHPInitScript 并添加组件` → 成功
|
||||
- ⚠️ `找不到 WXPCHPInitScript 类型` → SDK 未正确安装
|
||||
|
||||
### Q: DLL 加载失败?
|
||||
|
||||
**原因**:`direct_applet_sdk.dll` 必须在 **运行时** 的根目录(与 .exe 同级)
|
||||
|
||||
**解决**:确保宿主程序启动时提供 DLL
|
||||
|
||||
---
|
||||
|
||||
## 📝 技术细节
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| 触发接口 | `IPreprocessBuildWithReport` |
|
||||
| 回调优先级 | `callbackOrder = 0` |
|
||||
| 支持平台 | Windows x64, macOS |
|
||||
| 场景修改策略 | 临时打开 → 注入 → 保存 → 恢复 |
|
||||
| 类全名 | `WeChatWASM.WXPCHPInitScript` |
|
||||
|
||||
---
|
||||
|
||||
## 🔄 更新日志
|
||||
|
||||
### v1.1.0 (2026-03-02)
|
||||
- ✅ 重命名 `EmbeddedAppletSDK` → `WXPCHPInitScript`
|
||||
- ✅ 迁移脚本到 Runtime 目录(解决 Editor 脚本无法挂载问题)
|
||||
- ✅ 添加 `WeChatWASM` 命名空间
|
||||
- ✅ 移除模板复制机制(脚本现在内置于 SDK)
|
||||
|
||||
### v1.0.0 (2026-03-02)
|
||||
- ✅ 实现自动注入 EmbeddedAppletSDK GameObject
|
||||
- ✅ 智能检测并复制模板脚本
|
||||
- ✅ 兼容 Windows 和 macOS 构建
|
||||
7
Editor/PCHighPerformance/README_AutoInjection.md.meta
Normal file
7
Editor/PCHighPerformance/README_AutoInjection.md.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aacc596790ffe1aad08acb624adcdfaa
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
152
Editor/PCHighPerformance/TROUBLESHOOTING.md
Normal file
152
Editor/PCHighPerformance/TROUBLESHOOTING.md
Normal file
@ -0,0 +1,152 @@
|
||||
# PC高性能小游戏 - 问题排查指南
|
||||
|
||||
## 🐛 问题1:设置面板数据被清空
|
||||
|
||||
### 原因
|
||||
`OnLostFocus()` 时机不对,输入框的值可能还未同步到 `formInputData`
|
||||
|
||||
### 解决方案 ✅
|
||||
已修复:在 `OnSettingsGUI()` 中添加 `GUI.changed` 检测,每次输入时自动保存
|
||||
|
||||
---
|
||||
|
||||
## 🐛 问题2:ShowInfo 逻辑未执行
|
||||
|
||||
### 可能原因
|
||||
|
||||
#### 1. DLL 未找到 (最常见 90%)
|
||||
**症状**:运行 .exe 后没有任何弹窗
|
||||
**原因**:`direct_applet_sdk.dll` 不在 .exe 同级目录
|
||||
|
||||
**验证**:
|
||||
```bash
|
||||
# 检查导出目录结构
|
||||
导出路径/
|
||||
├── YourGame.exe
|
||||
├── direct_applet_sdk.dll ← 必须存在
|
||||
└── YourGame_Data/
|
||||
```
|
||||
|
||||
**解决**:
|
||||
- 确保 DLL 在运行时根目录
|
||||
- 查看 Unity Player.log:
|
||||
- Windows: `%APPDATA%\..\LocalLow\<CompanyName>\<ProductName>\Player.log`
|
||||
- 搜索关键字: `[WXPCHPInitScript]` 或 `DllNotFoundException`
|
||||
|
||||
---
|
||||
|
||||
#### 2. GameObject 未注入 (10%)
|
||||
**症状**:构建后场景中没有 `WXPCHPInitScript` 对象
|
||||
|
||||
**验证**:使用调试工具
|
||||
```
|
||||
Unity 菜单 → 微信小游戏 → PC高性能调试 → 检查SDK注入状态
|
||||
```
|
||||
|
||||
**可能的问题**:
|
||||
- ❌ Build Settings 中没有启用场景
|
||||
- ❌ 构建前 `PCHPBuildPreProcessor` 未执行
|
||||
- ❌ SDK 未正确安装
|
||||
|
||||
**解决**:
|
||||
1. 确保 Build Settings 有至少一个启用场景
|
||||
2. 查看 Console 日志:
|
||||
```
|
||||
[PC高性能小游戏] 开始预处理构建...
|
||||
[PC高性能小游戏] ✅ 已在 XXX 中创建 WXPCHPInitScript 并添加组件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 调试步骤(按顺序)
|
||||
|
||||
### Step 1: 检查 SDK 注入状态
|
||||
```
|
||||
Unity 菜单 → 微信小游戏 → PC高性能调试 → 检查SDK注入状态
|
||||
```
|
||||
|
||||
✅ 正常输出示例:
|
||||
```
|
||||
[构建场景] 启用的场景数: 1
|
||||
✅ 首场景: Assets/Scenes/Main.unity
|
||||
✅ 找到 SDK GameObject: WXPCHPInitScript
|
||||
✅ 挂载的脚本: WeChatWASM.WXPCHPInitScript
|
||||
|
||||
[类型加载检查]
|
||||
✅ WXPCHPInitScript 类型已加载
|
||||
程序集: WxWasmSDKRuntime
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 2: 检查导出路径
|
||||
```
|
||||
Unity 菜单 → 微信小游戏 → PC高性能调试 → 查看导出路径
|
||||
```
|
||||
|
||||
确认:
|
||||
- ✅ 目录存在
|
||||
- ✅ 有 .exe 文件
|
||||
|
||||
---
|
||||
|
||||
### Step 3: 运行 .exe 并查看日志
|
||||
|
||||
**日志位置**:
|
||||
```
|
||||
Windows: %APPDATA%\..\LocalLow\YourCompany\YourProduct\Player.log
|
||||
Mac: ~/Library/Logs/Company Name/Product Name/Player.log
|
||||
```
|
||||
|
||||
**搜索关键字**:
|
||||
```
|
||||
[WXPCHPInitScript]
|
||||
DllNotFoundException
|
||||
InitEmbeddedGameSDK
|
||||
```
|
||||
|
||||
**正常日志**:
|
||||
```
|
||||
[WXPCHPInitScript] ========== Awake 被调用 ==========
|
||||
[WXPCHPInitScript] GameObject 名称: WXPCHPInitScript
|
||||
[WXPCHPInitScript] ========== 开始初始化 ==========
|
||||
[WXPCHPInitScript] Step 1: 调用 InitEmbeddedGameSDK
|
||||
[WXPCHPInitScript] InitEmbeddedGameSDK 成功
|
||||
...
|
||||
```
|
||||
|
||||
**异常日志**:
|
||||
```
|
||||
DllNotFoundException: Unable to load DLL 'direct_applet_sdk.dll'
|
||||
→ 解决: 复制 DLL 到 .exe 同级目录
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 快速检查清单
|
||||
|
||||
- [ ] Build Settings 中有启用的场景
|
||||
- [ ] 构建时 Console 有 `[PC高性能小游戏] 预处理完成!` 日志
|
||||
- [ ] 导出目录包含 `.exe` 和 `direct_applet_sdk.dll`
|
||||
- [ ] 运行 .exe 后有弹窗或 Player.log 有日志
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 调试工具菜单
|
||||
|
||||
| 菜单项 | 功能 |
|
||||
|--------|------|
|
||||
| 检查SDK注入状态 | 验证场景中是否有 SDK 对象和脚本 |
|
||||
| 查看导出路径 | 显示配置的导出路径和状态 |
|
||||
| 打开导出目录 | 在文件管理器中打开导出目录 |
|
||||
|
||||
---
|
||||
|
||||
## 💡 常见错误代码
|
||||
|
||||
| 错误信息 | 原因 | 解决方法 |
|
||||
|----------|------|----------|
|
||||
| `DllNotFoundException` | DLL 未找到 | 复制 DLL 到 .exe 同级目录 |
|
||||
| `EntryPointNotFoundException` | 函数不存在 | 检查 DLL 版本是否匹配 |
|
||||
| `找不到 WXPCHPInitScript 类型` | SDK 未安装 | 重新导入 WX-WASM-SDK-V2 |
|
||||
| `GetActiveWindow 返回空句柄` | 窗口未创建 | 延迟初始化或检查 Unity Player 设置 |
|
||||
7
Editor/PCHighPerformance/TROUBLESHOOTING.md.meta
Normal file
7
Editor/PCHighPerformance/TROUBLESHOOTING.md.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b57398b893716f5822f5e196466fee6
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
267
Editor/PCHighPerformance/WXApkgPacker.cs
Normal file
267
Editor/PCHighPerformance/WXApkgPacker.cs
Normal file
@ -0,0 +1,267 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace WeChatWASM
|
||||
{
|
||||
/// <summary>
|
||||
/// wxapkg 文件打包器
|
||||
/// 将目录内容打包成 .wxapkg 格式
|
||||
///
|
||||
/// wxapkg 格式结构:
|
||||
/// 1. 头部段 (14 字节)
|
||||
/// - 起始标志: 1 字节 (0xBE)
|
||||
/// - 未知字段: 4 字节 (固定为 0)
|
||||
/// - 结束标志: 1 字节 (0xED)
|
||||
/// - 索引段长度: 4 字节 (大端序)
|
||||
/// - 数据段长度: 4 字节 (大端序)
|
||||
/// 2. 索引段
|
||||
/// - 文件数量: 4 字节 (大端序)
|
||||
/// - 文件信息块序列(每个文件):
|
||||
/// - 文件名长度: 4 字节 (大端序)
|
||||
/// - 文件名: 可变长度 (UTF-8)
|
||||
/// - 文件偏移: 4 字节 (大端序)
|
||||
/// - 文件长度: 4 字节 (大端序)
|
||||
/// 3. 数据段
|
||||
/// - 实际文件内容的二进制数据
|
||||
/// </summary>
|
||||
public static class WXApkgPacker
|
||||
{
|
||||
private const byte HEADER_MARK_START = 0xBE;
|
||||
private const byte HEADER_MARK_END = 0xED;
|
||||
private const int HEADER_SIZE = 14;
|
||||
|
||||
/// <summary>
|
||||
/// 文件信息结构
|
||||
/// </summary>
|
||||
private class FileInfo
|
||||
{
|
||||
public string RelativePath; // 相对路径(以 / 开头)
|
||||
public string FullPath; // 完整路径
|
||||
public int Size; // 文件大小
|
||||
public int Offset; // 在数据段中的偏移
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将目录打包成 wxapkg 文件
|
||||
/// </summary>
|
||||
/// <param name="sourceDir">源目录路径</param>
|
||||
/// <param name="outputPath">输出的 wxapkg 文件路径</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public static bool Pack(string sourceDir, string outputPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(sourceDir))
|
||||
{
|
||||
Debug.LogError($"[WXApkgPacker] 源目录不存在: {sourceDir}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 收集所有文件信息
|
||||
var files = CollectFiles(sourceDir);
|
||||
if (files.Count == 0)
|
||||
{
|
||||
Debug.LogError($"[WXApkgPacker] 目录为空: {sourceDir}");
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.Log($"[WXApkgPacker] 收集到 {files.Count} 个文件");
|
||||
|
||||
// 构建索引段
|
||||
byte[] indexData = BuildIndexSection(files);
|
||||
|
||||
// 构建数据段
|
||||
byte[] dataSection = BuildDataSection(files);
|
||||
|
||||
// 构建头部
|
||||
byte[] header = BuildHeader(indexData.Length, dataSection.Length);
|
||||
|
||||
// 确保输出目录存在
|
||||
string outputDir = Path.GetDirectoryName(outputPath);
|
||||
if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir))
|
||||
{
|
||||
Directory.CreateDirectory(outputDir);
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
using (var fs = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
fs.Write(header, 0, header.Length);
|
||||
fs.Write(indexData, 0, indexData.Length);
|
||||
fs.Write(dataSection, 0, dataSection.Length);
|
||||
}
|
||||
|
||||
long totalSize = header.Length + indexData.Length + dataSection.Length;
|
||||
Debug.Log($"[WXApkgPacker] 打包完成: {outputPath}");
|
||||
Debug.Log($"[WXApkgPacker] 文件大小: {totalSize / 1024.0 / 1024.0:F2} MB");
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[WXApkgPacker] 打包失败: {e.Message}");
|
||||
Debug.LogException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收集目录下所有文件
|
||||
/// </summary>
|
||||
private static List<FileInfo> CollectFiles(string sourceDir)
|
||||
{
|
||||
var files = new List<FileInfo>();
|
||||
var allFiles = Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories);
|
||||
|
||||
foreach (var filePath in allFiles)
|
||||
{
|
||||
// 跳过 .DS_Store 等隐藏文件
|
||||
string fileName = Path.GetFileName(filePath);
|
||||
if (fileName.StartsWith("."))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算相对路径(使用正斜杠,以 / 开头)
|
||||
string relativePath = filePath.Substring(sourceDir.Length);
|
||||
relativePath = relativePath.Replace('\\', '/');
|
||||
if (!relativePath.StartsWith("/"))
|
||||
{
|
||||
relativePath = "/" + relativePath;
|
||||
}
|
||||
|
||||
var info = new System.IO.FileInfo(filePath);
|
||||
files.Add(new FileInfo
|
||||
{
|
||||
RelativePath = relativePath,
|
||||
FullPath = filePath,
|
||||
Size = (int)info.Length
|
||||
});
|
||||
}
|
||||
|
||||
// 按路径排序,保持一致性
|
||||
files.Sort((a, b) => string.Compare(a.RelativePath, b.RelativePath, StringComparison.Ordinal));
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建头部段 (14 字节)
|
||||
/// </summary>
|
||||
private static byte[] BuildHeader(int indexLength, int dataLength)
|
||||
{
|
||||
byte[] header = new byte[HEADER_SIZE];
|
||||
|
||||
// 起始标志
|
||||
header[0] = HEADER_MARK_START;
|
||||
|
||||
// 4 字节未知字段 (固定为 0)
|
||||
header[1] = 0;
|
||||
header[2] = 0;
|
||||
header[3] = 0;
|
||||
header[4] = 0;
|
||||
|
||||
// 结束标志
|
||||
header[5] = HEADER_MARK_END;
|
||||
|
||||
// 索引段长度 (大端序)
|
||||
WriteInt32BE(header, 6, indexLength);
|
||||
|
||||
// 数据段长度 (大端序)
|
||||
WriteInt32BE(header, 10, dataLength);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建索引段
|
||||
/// </summary>
|
||||
private static byte[] BuildIndexSection(List<FileInfo> files)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var writer = new BinaryWriter(ms))
|
||||
{
|
||||
// 文件数量 (大端序)
|
||||
WriteInt32BE(writer, files.Count);
|
||||
|
||||
// 计算数据段起始偏移
|
||||
// 偏移量 = 头部大小 + 索引段大小
|
||||
// 需要先计算索引段大小
|
||||
int indexSize = 4; // 文件数量
|
||||
foreach (var file in files)
|
||||
{
|
||||
byte[] nameBytes = Encoding.UTF8.GetBytes(file.RelativePath);
|
||||
indexSize += 4 + nameBytes.Length + 4 + 4; // nameLen + name + offset + size
|
||||
}
|
||||
|
||||
int dataOffset = HEADER_SIZE + indexSize;
|
||||
|
||||
// 写入每个文件的索引信息
|
||||
foreach (var file in files)
|
||||
{
|
||||
byte[] nameBytes = Encoding.UTF8.GetBytes(file.RelativePath);
|
||||
|
||||
// 文件名长度 (大端序)
|
||||
WriteInt32BE(writer, nameBytes.Length);
|
||||
|
||||
// 文件名
|
||||
writer.Write(nameBytes);
|
||||
|
||||
// 文件偏移 (大端序)
|
||||
file.Offset = dataOffset;
|
||||
WriteInt32BE(writer, dataOffset);
|
||||
|
||||
// 文件大小 (大端序)
|
||||
WriteInt32BE(writer, file.Size);
|
||||
|
||||
// 更新下一个文件的偏移
|
||||
dataOffset += file.Size;
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建数据段
|
||||
/// </summary>
|
||||
private static byte[] BuildDataSection(List<FileInfo> files)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
byte[] content = File.ReadAllBytes(file.FullPath);
|
||||
ms.Write(content, 0, content.Length);
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入 32 位大端序整数到字节数组
|
||||
/// </summary>
|
||||
private static void WriteInt32BE(byte[] buffer, int offset, int value)
|
||||
{
|
||||
buffer[offset] = (byte)((value >> 24) & 0xFF);
|
||||
buffer[offset + 1] = (byte)((value >> 16) & 0xFF);
|
||||
buffer[offset + 2] = (byte)((value >> 8) & 0xFF);
|
||||
buffer[offset + 3] = (byte)(value & 0xFF);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入 32 位大端序整数到流
|
||||
/// </summary>
|
||||
private static void WriteInt32BE(BinaryWriter writer, int value)
|
||||
{
|
||||
writer.Write((byte)((value >> 24) & 0xFF));
|
||||
writer.Write((byte)((value >> 16) & 0xFF));
|
||||
writer.Write((byte)((value >> 8) & 0xFF));
|
||||
writer.Write((byte)(value & 0xFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Editor/PCHighPerformance/WXApkgPacker.cs.meta
Normal file
7
Editor/PCHighPerformance/WXApkgPacker.cs.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5e90582a5951eff22c3b110229de415
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
349
Editor/PCHighPerformance/WXPCHPBuildHelper.cs
Normal file
349
Editor/PCHighPerformance/WXPCHPBuildHelper.cs
Normal file
@ -0,0 +1,349 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build.Reporting;
|
||||
|
||||
namespace WeChatWASM
|
||||
{
|
||||
/// <summary>
|
||||
/// PC高性能小游戏构建辅助类
|
||||
/// 用于在微信小游戏转换工具面板中集成PC高性能模式构建
|
||||
/// </summary>
|
||||
public static class WXPCHPBuildHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// PC高性能构建产物目录名
|
||||
/// </summary>
|
||||
public const string PCHPOutputDir = "pchpcode";
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否开启了PC高性能模式
|
||||
/// </summary>
|
||||
public static bool IsPCHighPerformanceEnabled()
|
||||
{
|
||||
var config = UnityUtil.GetEditorConf();
|
||||
bool enabled = config != null && config.ProjectConf.EnablePCHighPerformance;
|
||||
Debug.Log($"[PC高性能模式] 检查配置: config={config != null}, EnablePCHighPerformance={config?.ProjectConf?.EnablePCHighPerformance}, 结果={enabled}");
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行PC高性能构建
|
||||
/// </summary>
|
||||
/// <param name="exportBasePath">导出基础路径(来自小游戏面板配置)</param>
|
||||
/// <returns>构建是否成功</returns>
|
||||
public static bool BuildPCHighPerformance(string exportBasePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(exportBasePath))
|
||||
{
|
||||
Debug.LogError("[PC高性能模式] 导出路径为空,无法构建");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确定构建目标平台
|
||||
var currentPlatform = Application.platform;
|
||||
BuildTarget buildTarget;
|
||||
string platformName;
|
||||
|
||||
if (currentPlatform == RuntimePlatform.OSXEditor)
|
||||
{
|
||||
buildTarget = BuildTarget.StandaloneOSX;
|
||||
platformName = "Mac";
|
||||
}
|
||||
else
|
||||
{
|
||||
buildTarget = BuildTarget.StandaloneWindows64;
|
||||
platformName = "Windows";
|
||||
}
|
||||
|
||||
// 构建输出路径:直接放在 minigame/pchpcode 目录下
|
||||
string pchpOutputPath = Path.Combine(exportBasePath, WXConvertCore.miniGameDir, PCHPOutputDir);
|
||||
|
||||
Debug.Log($"[PC高性能模式] 开始构建,目标平台: {platformName}");
|
||||
Debug.Log($"[PC高性能模式] 输出路径: {pchpOutputPath}");
|
||||
|
||||
// 保存当前构建目标
|
||||
var originalTarget = EditorUserBuildSettings.activeBuildTarget;
|
||||
var originalTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
|
||||
|
||||
try
|
||||
{
|
||||
// 切换构建目标(如果需要)
|
||||
if (originalTarget != buildTarget)
|
||||
{
|
||||
Debug.Log($"[PC高性能模式] 切换构建目标: {originalTarget} -> {buildTarget}");
|
||||
if (!EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, buildTarget))
|
||||
{
|
||||
Debug.LogError("[PC高性能模式] 切换构建目标失败");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 配置 Player Settings
|
||||
ConfigurePlayerSettings();
|
||||
|
||||
// 确保输出目录存在
|
||||
if (!Directory.Exists(pchpOutputPath))
|
||||
{
|
||||
Directory.CreateDirectory(pchpOutputPath);
|
||||
}
|
||||
|
||||
// 获取可执行文件路径
|
||||
string executablePath = GetExecutablePath(pchpOutputPath, buildTarget);
|
||||
|
||||
// 获取场景列表
|
||||
var scenes = GetEnabledScenes();
|
||||
if (scenes.Length == 0)
|
||||
{
|
||||
Debug.LogError("[PC高性能模式] 没有启用的场景,请在 Build Settings 中添加场景");
|
||||
EditorUtility.DisplayDialog("PC高性能模式构建失败", "没有启用的场景,请在 Build Settings 中添加场景", "确定");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 构建选项
|
||||
var buildOptions = BuildOptions.None;
|
||||
|
||||
// 执行构建
|
||||
Debug.Log($"[PC高性能模式] 执行构建,输出: {executablePath}");
|
||||
var report = BuildPipeline.BuildPlayer(scenes, executablePath, buildTarget, buildOptions);
|
||||
|
||||
// 检查构建结果
|
||||
if (report.summary.result == BuildResult.Succeeded)
|
||||
{
|
||||
Debug.Log($"[PC高性能模式] 构建成功! 耗时: {report.summary.totalTime.TotalSeconds:F2}秒");
|
||||
Debug.Log($"[PC高性能模式] 输出路径: {pchpOutputPath}");
|
||||
|
||||
// 打包成 wxapkg 格式(先打包到临时位置)
|
||||
string tempWxapkgPath = Path.Combine(exportBasePath, WXConvertCore.miniGameDir, $"{PCHPOutputDir}_temp.wxapkg");
|
||||
string finalWxapkgPath = Path.Combine(pchpOutputPath, $"{PCHPOutputDir}.wxapkg");
|
||||
|
||||
Debug.Log($"[PC高性能模式] 开始打包 wxapkg...");
|
||||
|
||||
if (WXApkgPacker.Pack(pchpOutputPath, tempWxapkgPath))
|
||||
{
|
||||
// 删除原始构建材料
|
||||
Debug.Log($"[PC高性能模式] 清理原始构建材料...");
|
||||
Directory.Delete(pchpOutputPath, true);
|
||||
|
||||
// 重新创建目录并移动 wxapkg
|
||||
Directory.CreateDirectory(pchpOutputPath);
|
||||
File.Move(tempWxapkgPath, finalWxapkgPath);
|
||||
|
||||
// 创建空的 game.js 文件
|
||||
string gameJsPath = Path.Combine(pchpOutputPath, "game.js");
|
||||
File.WriteAllText(gameJsPath, "");
|
||||
Debug.Log($"[PC高性能模式] 已创建 game.js: {gameJsPath}");
|
||||
|
||||
Debug.Log($"[PC高性能模式] wxapkg 打包完成: {finalWxapkgPath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[PC高性能模式] wxapkg 打包失败,保留原始构建产物");
|
||||
if (File.Exists(tempWxapkgPath))
|
||||
{
|
||||
File.Delete(tempWxapkgPath);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[PC高性能模式] 构建失败: {report.summary.result}");
|
||||
foreach (var step in report.steps)
|
||||
{
|
||||
foreach (var message in step.messages)
|
||||
{
|
||||
if (message.type == LogType.Error)
|
||||
{
|
||||
Debug.LogError($"[PC高性能模式] 构建错误: {message.content}");
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[PC高性能模式] 构建异常: {e.Message}");
|
||||
Debug.LogException(e);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 恢复到小游戏构建目标,确保微信小游戏转换工具能正常加载
|
||||
RestoreToMiniGamePlatform();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复到小游戏平台
|
||||
/// 团结引擎使用 WeixinMiniGame,Unity 使用 WebGL
|
||||
/// </summary>
|
||||
private static void RestoreToMiniGamePlatform()
|
||||
{
|
||||
#if TUANJIE_2022_3_OR_NEWER
|
||||
// 团结引擎:切换到 WeixinMiniGame 平台
|
||||
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WeixinMiniGame)
|
||||
{
|
||||
Debug.Log($"[PC高性能模式] 切换回 WeixinMiniGame 构建目标");
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.WeixinMiniGame, BuildTarget.WeixinMiniGame);
|
||||
}
|
||||
|
||||
// 激活微信小游戏子平台
|
||||
ActivateWeixinSubplatform();
|
||||
#else
|
||||
// Unity:切换到 WebGL 平台
|
||||
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL)
|
||||
{
|
||||
Debug.Log($"[PC高性能模式] 切换回 WebGL 构建目标");
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.WebGL, BuildTarget.WebGL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TUANJIE_2022_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// 激活微信小游戏子平台(通过反射调用,避免编译期对 MiniGameSubplatform 枚举的硬依赖)
|
||||
/// </summary>
|
||||
private static void ActivateWeixinSubplatform()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 通过反射查找 MiniGameSubplatform 枚举类型和 SetActiveSubplatform 方法
|
||||
// 因为 MiniGameSubplatform 可能在不同团结版本中命名空间不同
|
||||
var miniGameType = typeof(PlayerSettings).GetNestedType("MiniGame");
|
||||
if (miniGameType == null)
|
||||
{
|
||||
Debug.LogWarning("[PC高性能模式] 未找到 PlayerSettings.MiniGame 类型,跳过子平台激活");
|
||||
return;
|
||||
}
|
||||
|
||||
var setActiveMethod = miniGameType.GetMethod("SetActiveSubplatform",
|
||||
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
|
||||
if (setActiveMethod == null)
|
||||
{
|
||||
Debug.LogWarning("[PC高性能模式] 未找到 SetActiveSubplatform 方法,跳过子平台激活");
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找 MiniGameSubplatform 枚举
|
||||
System.Type subplatformEnumType = null;
|
||||
foreach (var asm in System.AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
subplatformEnumType = asm.GetType("MiniGameSubplatform") ?? asm.GetType("UnityEditor.MiniGameSubplatform");
|
||||
if (subplatformEnumType != null) break;
|
||||
}
|
||||
|
||||
if (subplatformEnumType == null)
|
||||
{
|
||||
Debug.LogWarning("[PC高性能模式] 未找到 MiniGameSubplatform 枚举类型,跳过子平台激活");
|
||||
return;
|
||||
}
|
||||
|
||||
var wechatValue = System.Enum.Parse(subplatformEnumType, "WeChat");
|
||||
setActiveMethod.Invoke(null, new object[] { wechatValue, true });
|
||||
Debug.Log("[PC高性能模式] 已激活微信小游戏子平台");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[PC高性能模式] 激活微信小游戏子平台失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 配置 Player Settings 用于 PC 高性能构建
|
||||
/// </summary>
|
||||
private static void ConfigurePlayerSettings()
|
||||
{
|
||||
// 设置窗口模式
|
||||
PlayerSettings.fullScreenMode = FullScreenMode.Windowed;
|
||||
|
||||
// 设置默认分辨率
|
||||
PlayerSettings.defaultScreenWidth = 1280;
|
||||
PlayerSettings.defaultScreenHeight = 720;
|
||||
|
||||
// 允许调整窗口大小
|
||||
PlayerSettings.resizableWindow = true;
|
||||
|
||||
// 处理 Windows 上 Linear 色彩空间与图形 API 的兼容性问题
|
||||
if (Application.platform == RuntimePlatform.WindowsEditor)
|
||||
{
|
||||
ConfigureWindowsGraphicsAPI();
|
||||
}
|
||||
|
||||
Debug.Log("[PC高性能模式] Player Settings 配置完成");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置 Windows 图形 API,解决 Linear 色彩空间兼容性问题
|
||||
/// </summary>
|
||||
private static void ConfigureWindowsGraphicsAPI()
|
||||
{
|
||||
// 检查当前色彩空间
|
||||
bool isLinear = PlayerSettings.colorSpace == ColorSpace.Linear;
|
||||
|
||||
if (isLinear)
|
||||
{
|
||||
// Linear 色彩空间需要 DX11 或更高版本
|
||||
// 禁用自动图形 API,手动指定兼容的 API
|
||||
PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.StandaloneWindows64, false);
|
||||
|
||||
var graphicsAPIs = new UnityEngine.Rendering.GraphicsDeviceType[]
|
||||
{
|
||||
UnityEngine.Rendering.GraphicsDeviceType.Direct3D11,
|
||||
UnityEngine.Rendering.GraphicsDeviceType.Direct3D12,
|
||||
UnityEngine.Rendering.GraphicsDeviceType.Vulkan
|
||||
};
|
||||
|
||||
PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, graphicsAPIs);
|
||||
Debug.Log("[PC高性能模式] 已配置 Windows 图形 API: D3D11, D3D12, Vulkan(Linear 色彩空间兼容)");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gamma 色彩空间,使用默认图形 API 即可
|
||||
PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.StandaloneWindows64, true);
|
||||
Debug.Log("[PC高性能模式] 使用默认 Windows 图形 API(Gamma 色彩空间)");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取可执行文件路径
|
||||
/// </summary>
|
||||
private static string GetExecutablePath(string outputPath, BuildTarget target)
|
||||
{
|
||||
string productName = PlayerSettings.productName;
|
||||
if (string.IsNullOrEmpty(productName))
|
||||
{
|
||||
productName = "Game";
|
||||
}
|
||||
|
||||
if (target == BuildTarget.StandaloneOSX)
|
||||
{
|
||||
return Path.Combine(outputPath, $"{productName}.app");
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.Combine(outputPath, $"{productName}.exe");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取启用的场景列表
|
||||
/// </summary>
|
||||
private static string[] GetEnabledScenes()
|
||||
{
|
||||
var scenes = new List<string>();
|
||||
foreach (var scene in EditorBuildSettings.scenes)
|
||||
{
|
||||
if (scene.enabled)
|
||||
{
|
||||
scenes.Add(scene.path);
|
||||
}
|
||||
}
|
||||
return scenes.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Editor/PCHighPerformance/WXPCHPBuildHelper.cs.meta
Normal file
7
Editor/PCHighPerformance/WXPCHPBuildHelper.cs.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1455a91f4635862b70423ea92eff07bb
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Editor/PCHighPerformance/WXPCHPWindow.cs
Normal file
39
Editor/PCHighPerformance/WXPCHPWindow.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace WeChatWASM
|
||||
{
|
||||
|
||||
public class WXPCHPWin : EditorWindow
|
||||
{
|
||||
[MenuItem("微信小游戏 / 转换PC高性能模式", false, 3)]
|
||||
public static void Open()
|
||||
{
|
||||
var win = GetWindow(typeof(WXPCHPWin), false, "PC高性能模式转换工具");
|
||||
win.minSize = new Vector2(350, 200);
|
||||
win.position = new Rect(150, 150, 500, 300);
|
||||
win.Show();
|
||||
}
|
||||
|
||||
public void OnFocus()
|
||||
{
|
||||
WXPCSettingsHelperInterface.helper.OnFocus();
|
||||
}
|
||||
|
||||
public void OnLostFocus()
|
||||
{
|
||||
WXPCSettingsHelperInterface.helper.OnLostFocus();
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
{
|
||||
WXPCSettingsHelperInterface.helper.OnDisable();
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
WXPCSettingsHelperInterface.helper.OnSettingsGUI(this);
|
||||
WXPCSettingsHelperInterface.helper.OnBuildButtonGUI(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Editor/PCHighPerformance/WXPCHPWindow.cs.meta
Normal file
7
Editor/PCHighPerformance/WXPCHPWindow.cs.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f0df5132a2e6c4a2e5541e3472a6422
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
488
Editor/PCHighPerformance/WXPCSettingHelper.cs
Normal file
488
Editor/PCHighPerformance/WXPCSettingHelper.cs
Normal file
@ -0,0 +1,488 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEditor.SceneManagement;
|
||||
using System.IO;
|
||||
|
||||
namespace WeChatWASM
|
||||
{
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class WXPCSettingsHelperInterface
|
||||
{
|
||||
public static WXPCSettingHelper helper = new WXPCSettingHelper();
|
||||
}
|
||||
|
||||
public class WXPCSettingHelper
|
||||
{
|
||||
public static string projectRootPath;
|
||||
|
||||
// SDK 脚本常量
|
||||
private const string SDK_CLASS_NAME = "WeChatWASM.WXPCHPInitScript";
|
||||
private const string SDK_GAMEOBJECT_NAME = "WXPCHPInitScript";
|
||||
|
||||
public WXPCSettingHelper()
|
||||
{
|
||||
projectRootPath = Path.GetFullPath(Application.dataPath + "/../");
|
||||
}
|
||||
|
||||
// UI 状态
|
||||
private Vector2 scrollRoot;
|
||||
|
||||
// 表单数据
|
||||
private Dictionary<string, string> formInputData = new Dictionary<string, string>();
|
||||
|
||||
// 配置文件路径
|
||||
private string ConfigFilePath => Path.Combine(Application.dataPath, "WX-WASM-SDK-V2", "Editor", "PCHighPerformance", "PCHPConfig.json");
|
||||
|
||||
public void OnFocus()
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
public void OnLostFocus()
|
||||
{
|
||||
SaveData();
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
{
|
||||
SaveData();
|
||||
}
|
||||
|
||||
public void OnSettingsGUI(EditorWindow window)
|
||||
{
|
||||
scrollRoot = EditorGUILayout.BeginScrollView(scrollRoot);
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
// 标题
|
||||
var titleStyle = new GUIStyle(EditorStyles.boldLabel)
|
||||
{
|
||||
fontSize = 14,
|
||||
alignment = TextAnchor.MiddleCenter
|
||||
};
|
||||
EditorGUILayout.LabelField("PC高性能模式转换", titleStyle);
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
EditorGUILayout.BeginVertical("frameBox", GUILayout.ExpandWidth(true));
|
||||
|
||||
// 导出路径 - 支持相对路径和选择目录
|
||||
FormInputWithFolderSelectorAndHelp("exportPath", "导出路径", "Standalone 构建产物的输出目录,支持相对路径(相对项目根目录)或绝对路径");
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
// 提示信息
|
||||
EditorGUILayout.HelpBox(
|
||||
"点击「生成并转换」将执行以下操作:\n" +
|
||||
"1. 向首场景注入 WXPCHPInitScript 脚本\n" +
|
||||
"2. 构建 Standalone 可执行文件\n" +
|
||||
"3. SDK 初始化时会弹窗展示各步骤进度",
|
||||
MessageType.Info);
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
// 检测 GUI 变化并自动保存
|
||||
if (GUI.changed)
|
||||
{
|
||||
SaveData();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBuildButtonGUI(EditorWindow window)
|
||||
{
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// 生成并转换按钮
|
||||
var buttonStyle = new GUIStyle(GUI.skin.button)
|
||||
{
|
||||
fontSize = 13,
|
||||
fontStyle = FontStyle.Bold
|
||||
};
|
||||
if (GUILayout.Button("生成并转换", buttonStyle, GUILayout.Width(160), GUILayout.Height(36)))
|
||||
{
|
||||
OnBuildButtonClicked(window);
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击生成并转换按钮
|
||||
/// </summary>
|
||||
private void OnBuildButtonClicked(EditorWindow window)
|
||||
{
|
||||
SaveData();
|
||||
|
||||
var exportPath = GetDataInput("exportPath");
|
||||
if (string.IsNullOrEmpty(exportPath.Trim()))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "请先设置导出路径", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算完整输出路径
|
||||
string fullExportPath;
|
||||
if (Path.IsPathRooted(exportPath))
|
||||
{
|
||||
fullExportPath = exportPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
fullExportPath = Path.Combine(projectRootPath, exportPath);
|
||||
}
|
||||
|
||||
Debug.Log($"[PC高性能模式] 导出路径: {fullExportPath}");
|
||||
|
||||
// 确定构建平台
|
||||
BuildTarget buildTarget;
|
||||
string platformName;
|
||||
if (Application.platform == RuntimePlatform.OSXEditor)
|
||||
{
|
||||
buildTarget = BuildTarget.StandaloneOSX;
|
||||
platformName = "macOS";
|
||||
}
|
||||
else
|
||||
{
|
||||
buildTarget = BuildTarget.StandaloneWindows64;
|
||||
platformName = "Windows x64";
|
||||
}
|
||||
|
||||
Debug.Log($"[PC高性能模式] 目标平台: {platformName}");
|
||||
|
||||
try
|
||||
{
|
||||
// Step 1: 注入 WXPCHPInitScript 到首场景
|
||||
EditorUtility.DisplayProgressBar("PC高性能模式", "正在向首场景注入 SDK 脚本...", 0.1f);
|
||||
InjectSDKToFirstScene();
|
||||
|
||||
// Step 2: 切换构建目标
|
||||
EditorUtility.DisplayProgressBar("PC高性能模式", "正在切换构建目标...", 0.2f);
|
||||
var originalTarget = EditorUserBuildSettings.activeBuildTarget;
|
||||
if (originalTarget != buildTarget)
|
||||
{
|
||||
Debug.Log($"[PC高性能模式] 切换构建目标: {originalTarget} -> {buildTarget}");
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, buildTarget);
|
||||
}
|
||||
|
||||
// Step 3: 配置 Player Settings
|
||||
EditorUtility.DisplayProgressBar("PC高性能模式", "正在配置 Player Settings...", 0.3f);
|
||||
ConfigurePlayerSettings();
|
||||
|
||||
// Step 4: 准备输出目录
|
||||
if (!Directory.Exists(fullExportPath))
|
||||
{
|
||||
Directory.CreateDirectory(fullExportPath);
|
||||
}
|
||||
|
||||
string productName = PlayerSettings.productName;
|
||||
if (string.IsNullOrEmpty(productName)) productName = "Game";
|
||||
|
||||
string executablePath = buildTarget == BuildTarget.StandaloneOSX
|
||||
? Path.Combine(fullExportPath, $"{productName}.app")
|
||||
: Path.Combine(fullExportPath, $"{productName}.exe");
|
||||
|
||||
// Step 5: 获取场景列表
|
||||
var scenes = GetEnabledScenes();
|
||||
if (scenes.Length == 0)
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
EditorUtility.DisplayDialog("构建失败", "没有启用的场景,请在 Build Settings 中添加场景", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 6: 执行构建
|
||||
EditorUtility.DisplayProgressBar("PC高性能模式", "正在构建 Standalone...", 0.5f);
|
||||
Debug.Log($"[PC高性能模式] 开始构建,输出: {executablePath}");
|
||||
|
||||
var report = BuildPipeline.BuildPlayer(scenes, executablePath, buildTarget, BuildOptions.None);
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
if (report.summary.result == BuildResult.Succeeded)
|
||||
{
|
||||
Debug.Log($"[PC高性能模式] 构建成功! 耗时: {report.summary.totalTime.TotalSeconds:F2}秒");
|
||||
|
||||
if (EditorUtility.DisplayDialog("构建成功",
|
||||
$"PC高性能模式构建完成!\n\n平台: {platformName}\n耗时: {report.summary.totalTime.TotalSeconds:F2}秒\n输出: {fullExportPath}",
|
||||
"打开目录", "关闭"))
|
||||
{
|
||||
EditorUtility.RevealInFinder(fullExportPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[PC高性能模式] 构建失败: {report.summary.result}");
|
||||
EditorUtility.DisplayDialog("构建失败", $"构建失败: {report.summary.result}\n\n请查看 Console 获取详细错误信息", "确定");
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
Debug.LogError($"[PC高性能模式] 构建异常: {e.Message}\n{e.StackTrace}");
|
||||
EditorUtility.DisplayDialog("构建异常", $"构建过程中发生异常:\n{e.Message}", "确定");
|
||||
}
|
||||
}
|
||||
|
||||
#region Scene Injection
|
||||
|
||||
/// <summary>
|
||||
/// 向首场景注入 WXPCHPInitScript
|
||||
/// </summary>
|
||||
private void InjectSDKToFirstScene()
|
||||
{
|
||||
// 查找脚本类型
|
||||
var sdkType = FindTypeInAllAssemblies(SDK_CLASS_NAME);
|
||||
if (sdkType == null)
|
||||
{
|
||||
throw new System.Exception($"找不到 {SDK_CLASS_NAME} 类型,请确保 WX-WASM-SDK-V2 已正确安装");
|
||||
}
|
||||
|
||||
var assemblyName = sdkType.Assembly.GetName().Name;
|
||||
Debug.Log($"[PC高性能模式] 找到 WXPCHPInitScript,程序集: {assemblyName}");
|
||||
|
||||
if (assemblyName.Contains("Editor"))
|
||||
{
|
||||
throw new System.Exception("WXPCHPInitScript 在 Editor 程序集中,无法用于 Runtime 构建!请确保脚本放在 Runtime 目录下");
|
||||
}
|
||||
|
||||
// 获取首场景
|
||||
var firstScenePath = GetFirstEnabledScenePath();
|
||||
if (string.IsNullOrEmpty(firstScenePath))
|
||||
{
|
||||
throw new System.Exception("没有启用的场景,请在 Build Settings 中添加场景");
|
||||
}
|
||||
|
||||
// 打开首场景
|
||||
var currentScenes = EditorSceneManager.GetSceneManagerSetup();
|
||||
var scene = EditorSceneManager.OpenScene(firstScenePath, OpenSceneMode.Single);
|
||||
|
||||
// 清理旧对象
|
||||
var oldSDK = GameObject.Find("EmbeddedAppletSDK");
|
||||
if (oldSDK != null)
|
||||
{
|
||||
Debug.Log("[PC高性能模式] 删除旧的 EmbeddedAppletSDK 对象");
|
||||
GameObject.DestroyImmediate(oldSDK);
|
||||
}
|
||||
|
||||
// 删除已存在的同名对象(避免重复)
|
||||
var existingSDK = GameObject.Find(SDK_GAMEOBJECT_NAME);
|
||||
if (existingSDK != null)
|
||||
{
|
||||
Debug.Log($"[PC高性能模式] 删除已存在的 {SDK_GAMEOBJECT_NAME},重新创建");
|
||||
GameObject.DestroyImmediate(existingSDK);
|
||||
}
|
||||
|
||||
// 创建新的 GameObject 并添加 WXPCHPInitScript
|
||||
var sdkObject = new GameObject(SDK_GAMEOBJECT_NAME);
|
||||
sdkObject.AddComponent(sdkType);
|
||||
Debug.Log($"[PC高性能模式] ✅ 已在场景 [{scene.name}] 创建 {SDK_GAMEOBJECT_NAME} 并挂载 WXPCHPInitScript");
|
||||
|
||||
// 保存场景
|
||||
EditorSceneManager.MarkSceneDirty(scene);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
|
||||
// 恢复场景状态
|
||||
if (currentScenes != null && currentScenes.Length > 0)
|
||||
{
|
||||
EditorSceneManager.RestoreSceneManagerSetup(currentScenes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在所有程序集中查找类型
|
||||
/// </summary>
|
||||
private System.Type FindTypeInAllAssemblies(string typeName)
|
||||
{
|
||||
foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
var type = assembly.GetType(typeName);
|
||||
if (type != null) return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取首个启用的场景路径
|
||||
/// </summary>
|
||||
private string GetFirstEnabledScenePath()
|
||||
{
|
||||
foreach (var scene in EditorBuildSettings.scenes)
|
||||
{
|
||||
if (scene.enabled) return scene.path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Build Configuration
|
||||
|
||||
/// <summary>
|
||||
/// 配置 Player Settings
|
||||
/// </summary>
|
||||
private void ConfigurePlayerSettings()
|
||||
{
|
||||
PlayerSettings.fullScreenMode = FullScreenMode.Windowed;
|
||||
PlayerSettings.defaultScreenWidth = 1280;
|
||||
PlayerSettings.defaultScreenHeight = 720;
|
||||
PlayerSettings.resizableWindow = true;
|
||||
|
||||
// Windows Linear 色彩空间需要 DX11+
|
||||
if (Application.platform == RuntimePlatform.WindowsEditor &&
|
||||
PlayerSettings.colorSpace == ColorSpace.Linear)
|
||||
{
|
||||
PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.StandaloneWindows64, false);
|
||||
PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, new[]
|
||||
{
|
||||
UnityEngine.Rendering.GraphicsDeviceType.Direct3D11,
|
||||
UnityEngine.Rendering.GraphicsDeviceType.Direct3D12,
|
||||
UnityEngine.Rendering.GraphicsDeviceType.Vulkan
|
||||
});
|
||||
}
|
||||
|
||||
Debug.Log("[PC高性能模式] Player Settings 配置完成");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取启用的场景列表
|
||||
/// </summary>
|
||||
private string[] GetEnabledScenes()
|
||||
{
|
||||
var scenes = new List<string>();
|
||||
foreach (var scene in EditorBuildSettings.scenes)
|
||||
{
|
||||
if (scene.enabled) scenes.Add(scene.path);
|
||||
}
|
||||
return scenes.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data Persistence
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
if (File.Exists(ConfigFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(ConfigFilePath);
|
||||
var config = JsonUtility.FromJson<PCHPConfigData>(json);
|
||||
if (config != null)
|
||||
{
|
||||
SetData("exportPath", config.exportPath ?? "");
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[PC高性能模式] 加载配置失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetData("exportPath", "");
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveData()
|
||||
{
|
||||
try
|
||||
{
|
||||
var config = new PCHPConfigData
|
||||
{
|
||||
exportPath = GetDataInput("exportPath")
|
||||
};
|
||||
|
||||
var directory = Path.GetDirectoryName(ConfigFilePath);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
var json = JsonUtility.ToJson(config, true);
|
||||
File.WriteAllText(ConfigFilePath, json);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[PC高性能模式] 保存配置失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private string GetDataInput(string target)
|
||||
{
|
||||
return formInputData.ContainsKey(target) ? formInputData[target] : "";
|
||||
}
|
||||
|
||||
private void SetData(string target, string value)
|
||||
{
|
||||
formInputData[target] = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GUI Helpers
|
||||
|
||||
/// <summary>
|
||||
/// 绘制带文件夹选择器和帮助提示的输入框
|
||||
/// </summary>
|
||||
private void FormInputWithFolderSelectorAndHelp(string target, string label, string help = null)
|
||||
{
|
||||
if (!formInputData.ContainsKey(target))
|
||||
{
|
||||
formInputData[target] = "";
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(string.Empty, GUILayout.Width(10));
|
||||
|
||||
var displayLabel = help == null ? label : $"{label}(?)";
|
||||
GUILayout.Label(new GUIContent(displayLabel, help), GUILayout.Width(140));
|
||||
|
||||
formInputData[target] = GUILayout.TextField(formInputData[target], GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - 275));
|
||||
|
||||
if (GUILayout.Button("选择", GUILayout.Width(60)))
|
||||
{
|
||||
var selectedPath = EditorUtility.OpenFolderPanel("选择导出目录", projectRootPath, "");
|
||||
if (!string.IsNullOrEmpty(selectedPath))
|
||||
{
|
||||
if (selectedPath.StartsWith(projectRootPath))
|
||||
{
|
||||
var relativePath = selectedPath.Substring(projectRootPath.Length);
|
||||
if (relativePath.StartsWith("/") || relativePath.StartsWith("\\"))
|
||||
{
|
||||
relativePath = relativePath.Substring(1);
|
||||
}
|
||||
formInputData[target] = relativePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
formInputData[target] = selectedPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PC高性能小游戏配置数据
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class PCHPConfigData
|
||||
{
|
||||
public string exportPath;
|
||||
}
|
||||
}
|
||||
7
Editor/PCHighPerformance/WXPCSettingHelper.cs.meta
Normal file
7
Editor/PCHighPerformance/WXPCSettingHelper.cs.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 769878c6cc6489f59f3bca6835614c27
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -273,6 +273,24 @@ namespace WeChatWASM
|
||||
finishExport();
|
||||
}
|
||||
}
|
||||
|
||||
// PC高性能模式:在小游戏构建完成后构建PC版本
|
||||
if (buildWebGL && WXPCHPBuildHelper.IsPCHighPerformanceEnabled())
|
||||
{
|
||||
Debug.Log("[微信小游戏] 小游戏构建完成,开始构建PC高性能版本...");
|
||||
|
||||
if (!WXPCHPBuildHelper.BuildPCHighPerformance(config.ProjectConf.DST))
|
||||
{
|
||||
Debug.LogError("[微信小游戏] PC高性能模式构建失败");
|
||||
EditorUtility.DisplayDialog("PC高性能模式构建失败",
|
||||
"PC高性能版本构建失败,但小游戏版本已构建成功。", "确定");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[微信小游戏] PC高性能版本构建完成!");
|
||||
}
|
||||
}
|
||||
|
||||
return WXExportError.SUCCEED;
|
||||
}
|
||||
|
||||
|
||||
@ -121,6 +121,14 @@ namespace WeChatWASM
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
foldPCHighPerformance = EditorGUILayout.Foldout(foldPCHighPerformance, "PC高性能模式选项");
|
||||
if (foldPCHighPerformance)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("frameBox", GUILayout.ExpandWidth(true));
|
||||
OnSettingPCHighPerformance();
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
foldDebugOptions = EditorGUILayout.Foldout(foldDebugOptions, "调试编译选项");
|
||||
if (foldDebugOptions)
|
||||
{
|
||||
@ -233,6 +241,14 @@ namespace WeChatWASM
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
foldPCHighPerformance = EditorGUILayout.Foldout(foldPCHighPerformance, "PC高性能模式");
|
||||
if (foldPCHighPerformance)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("frameBox", GUILayout.ExpandWidth(true));
|
||||
OnSettingPCHighPerformance();
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
foldDebugOptions = EditorGUILayout.Foldout(foldDebugOptions, "调试编译选项");
|
||||
if (foldDebugOptions)
|
||||
{
|
||||
@ -374,6 +390,11 @@ namespace WeChatWASM
|
||||
formCheckbox("disableMultiTouch", "禁止多点触控");
|
||||
}
|
||||
|
||||
private void OnSettingPCHighPerformance()
|
||||
{
|
||||
formCheckbox("enablePCHighPerformance", "PC高性能模式(?)", "勾选后将在构建时同时构建PC端高性能版本,构建产物会放到导出路径下的PCHP目录");
|
||||
}
|
||||
|
||||
private void OnSettingDebugOptions(bool showDevBuild)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("frameBox", GUILayout.ExpandWidth(true));
|
||||
@ -519,6 +540,7 @@ namespace WeChatWASM
|
||||
private bool foldBaseInfo = true;
|
||||
private bool foldLoadingConfig = true;
|
||||
private bool foldSDKOptions = true;
|
||||
private bool foldPCHighPerformance = true;
|
||||
private bool foldDebugOptions = true;
|
||||
private bool foldInstantGame = false;
|
||||
private bool foldFontOptions = false;
|
||||
@ -657,6 +679,7 @@ namespace WeChatWASM
|
||||
this.setData("loadingBarWidth", ProjectConf.loadingBarWidth.ToString());
|
||||
this.setData("needCheckUpdate", ProjectConf.needCheckUpdate);
|
||||
this.setData("disableHighPerformanceFallback", ProjectConf.disableHighPerformanceFallback);
|
||||
this.setData("enablePCHighPerformance", ProjectConf.EnablePCHighPerformance);
|
||||
}
|
||||
|
||||
private void loadSDKOptionsData(SDKOptions SDKOptions)
|
||||
@ -784,6 +807,7 @@ namespace WeChatWASM
|
||||
ProjectConf.loadingBarWidth = int.Parse(this.getDataInput("loadingBarWidth"));
|
||||
ProjectConf.needCheckUpdate = this.getDataCheckbox("needCheckUpdate");
|
||||
ProjectConf.disableHighPerformanceFallback = this.getDataCheckbox("disableHighPerformanceFallback");
|
||||
ProjectConf.EnablePCHighPerformance = this.getDataCheckbox("enablePCHighPerformance");
|
||||
}
|
||||
|
||||
private void saveSDKOptionsData(SDKOptions SDKOptions)
|
||||
@ -873,6 +897,7 @@ namespace WeChatWASM
|
||||
_ProjectConf.loadingBarWidth = ProjectConf.FindPropertyRelative("loadingBarWidth").intValue;
|
||||
_ProjectConf.needCheckUpdate = ProjectConf.FindPropertyRelative("needCheckUpdate").boolValue;
|
||||
_ProjectConf.disableHighPerformanceFallback = ProjectConf.FindPropertyRelative("disableHighPerformanceFallback").boolValue;
|
||||
_ProjectConf.EnablePCHighPerformance = ProjectConf.FindPropertyRelative("EnablePCHighPerformance").boolValue;
|
||||
}
|
||||
private void serializeProjectConf(WXProjectConf _ProjectConf, SerializedProperty ProjectConf)
|
||||
{
|
||||
@ -902,6 +927,7 @@ namespace WeChatWASM
|
||||
ProjectConf.FindPropertyRelative("loadingBarWidth").intValue = _ProjectConf.loadingBarWidth;
|
||||
ProjectConf.FindPropertyRelative("needCheckUpdate").boolValue = _ProjectConf.needCheckUpdate;
|
||||
ProjectConf.FindPropertyRelative("disableHighPerformanceFallback").boolValue = _ProjectConf.disableHighPerformanceFallback;
|
||||
ProjectConf.FindPropertyRelative("EnablePCHighPerformance").boolValue = _ProjectConf.EnablePCHighPerformance;
|
||||
|
||||
//miniGameProperty.FindPropertyRelative("m_AutomaticFillInstantGame").boolValue = getDataCheckbox("m_AutomaticFillInstantGame");
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ namespace WeChatWASM
|
||||
{
|
||||
public class WXPluginVersion
|
||||
{
|
||||
public static string pluginVersion = "202603160259"; // 这一行不要改他,导出的时候会自动替换
|
||||
public static string pluginVersion = "202603250323"; // 这一行不要改他,导出的时候会自动替换
|
||||
}
|
||||
|
||||
public class WXPluginConf
|
||||
|
||||
Binary file not shown.
@ -493,6 +493,11 @@
|
||||
注意:不要随意修改,默认值为0,0表示不限制
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:WeChatWASM.WXProjectConf.EnablePCHighPerformance">
|
||||
<summary>
|
||||
是否开启PC高性能模式
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:WeChatWASM.CompressTexture.halfSize">
|
||||
<summary>
|
||||
自动将图片尺寸减小一半
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7330c57dbe403f6a6825fe311f4436ca
|
||||
guid: fc63c7c713805714b1dd0992ae9dcff2
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
8
Runtime/Examples.meta
Normal file
8
Runtime/Examples.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8fdca948fd6a64887c0534f384f283f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
257
Runtime/Examples/PCHPTestExample.cs
Normal file
257
Runtime/Examples/PCHPTestExample.cs
Normal file
@ -0,0 +1,257 @@
|
||||
using UnityEngine;
|
||||
using WeChatWASM;
|
||||
|
||||
namespace WeChatWASM.Examples
|
||||
{
|
||||
/// <summary>
|
||||
/// PC高性能小游戏通信测试示例
|
||||
///
|
||||
/// 通信链路:
|
||||
/// 1. C# 调用 ShowToast
|
||||
/// 2. WXPCHPInitScript.CallWXAPI 构建 PCHPRequestMessage
|
||||
/// 3. SendMsgAsync -> direct_applet_sdk.dll -> 内核
|
||||
/// 4. 内核 -> 基础库 pc-adapter -> game.js
|
||||
/// 5. game.js 执行 wx.showToast
|
||||
/// 6. 回调 -> 基础库 -> 内核 -> DLL -> HandleAsyncMessage
|
||||
/// 7. 解析 PCHPResponseMessage -> 触发 C# 回调
|
||||
/// </summary>
|
||||
public class PCHPTestExample : MonoBehaviour
|
||||
{
|
||||
private WXPCHighPerformanceManager _pcManager;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Debug.Log("[PCHPTestExample] Start - 获取 PC 高性能管理器");
|
||||
|
||||
#if UNITY_STANDALONE_WIN
|
||||
_pcManager = WXPCHighPerformanceManager.GetInstance();
|
||||
|
||||
if (_pcManager != null && _pcManager.IsSupported)
|
||||
{
|
||||
Debug.Log("[PCHPTestExample] PC 高性能模式已支持!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[PCHPTestExample] PC 高性能模式不可用");
|
||||
}
|
||||
#else
|
||||
Debug.Log("[PCHPTestExample] 当前平台非 Windows,PC 高性能模式不可用");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ShowToast - 在 Inspector 中调用或通过 UI 按钮调用
|
||||
/// </summary>
|
||||
[ContextMenu("Test ShowToast")]
|
||||
public void TestShowToast()
|
||||
{
|
||||
if (_pcManager == null || !_pcManager.IsSupported)
|
||||
{
|
||||
Debug.LogError("[PCHPTestExample] PC 高性能模式不可用");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[PCHPTestExample] 调用 ShowToast...");
|
||||
|
||||
_pcManager.ShowToast(
|
||||
new PCHPShowToastOption
|
||||
{
|
||||
title = "Hello from Unity!",
|
||||
icon = "success",
|
||||
duration = 2000,
|
||||
mask = false
|
||||
},
|
||||
success: (res) =>
|
||||
{
|
||||
Debug.Log($"[PCHPTestExample] ShowToast 成功: {res.errMsg}");
|
||||
},
|
||||
fail: (res) =>
|
||||
{
|
||||
Debug.LogError($"[PCHPTestExample] ShowToast 失败: {res.errMsg}");
|
||||
},
|
||||
complete: (res) =>
|
||||
{
|
||||
Debug.Log($"[PCHPTestExample] ShowToast 完成");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ShowModal - 在 Inspector 中调用或通过 UI 按钮调用
|
||||
/// </summary>
|
||||
[ContextMenu("Test ShowModal")]
|
||||
public void TestShowModal()
|
||||
{
|
||||
if (_pcManager == null || !_pcManager.IsSupported)
|
||||
{
|
||||
Debug.LogError("[PCHPTestExample] PC 高性能模式不可用");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[PCHPTestExample] 调用 ShowModal...");
|
||||
|
||||
_pcManager.ShowModal(
|
||||
new PCHPShowModalOption
|
||||
{
|
||||
title = "提示",
|
||||
content = "这是一个来自 Unity 的模态框测试",
|
||||
showCancel = true,
|
||||
cancelText = "取消",
|
||||
confirmText = "确定"
|
||||
},
|
||||
success: (res) =>
|
||||
{
|
||||
if (res.confirm)
|
||||
{
|
||||
Debug.Log("[PCHPTestExample] 用户点击了确定");
|
||||
}
|
||||
else if (res.cancel)
|
||||
{
|
||||
Debug.Log("[PCHPTestExample] 用户点击了取消");
|
||||
}
|
||||
},
|
||||
fail: (res) =>
|
||||
{
|
||||
Debug.LogError($"[PCHPTestExample] ShowModal 失败: {res.errMsg}");
|
||||
},
|
||||
complete: (res) =>
|
||||
{
|
||||
Debug.Log($"[PCHPTestExample] ShowModal 完成");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 ShowLoading - 在 Inspector 中调用或通过 UI 按钮调用
|
||||
/// </summary>
|
||||
[ContextMenu("Test ShowLoading")]
|
||||
public void TestShowLoading()
|
||||
{
|
||||
if (_pcManager == null || !_pcManager.IsSupported)
|
||||
{
|
||||
Debug.LogError("[PCHPTestExample] PC 高性能模式不可用");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[PCHPTestExample] 调用 ShowLoading...");
|
||||
|
||||
_pcManager.ShowLoading("加载中...", true,
|
||||
success: (res) =>
|
||||
{
|
||||
Debug.Log($"[PCHPTestExample] ShowLoading 成功");
|
||||
|
||||
// 2秒后隐藏
|
||||
StartCoroutine(HideLoadingAfterDelay(2f));
|
||||
},
|
||||
fail: (res) =>
|
||||
{
|
||||
Debug.LogError($"[PCHPTestExample] ShowLoading 失败: {res.errMsg}");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator HideLoadingAfterDelay(float delay)
|
||||
{
|
||||
yield return new WaitForSeconds(delay);
|
||||
|
||||
_pcManager?.HideLoading(
|
||||
success: (res) =>
|
||||
{
|
||||
Debug.Log("[PCHPTestExample] HideLoading 成功");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试通用 API 调用
|
||||
/// </summary>
|
||||
[ContextMenu("Test Generic API Call")]
|
||||
public void TestGenericAPICall()
|
||||
{
|
||||
if (_pcManager == null || !_pcManager.IsSupported)
|
||||
{
|
||||
Debug.LogError("[PCHPTestExample] PC 高性能模式不可用");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[PCHPTestExample] 调用通用 API (getSystemInfoSync)...");
|
||||
|
||||
// 示例:调用任意 wx API
|
||||
_pcManager.CallWXAPI(
|
||||
"getSystemInfo",
|
||||
new { }, // 无参数
|
||||
onSuccess: (res) =>
|
||||
{
|
||||
Debug.Log($"[PCHPTestExample] getSystemInfo 成功: {res}");
|
||||
},
|
||||
onFail: (res) =>
|
||||
{
|
||||
Debug.LogError($"[PCHPTestExample] getSystemInfo 失败: {res}");
|
||||
},
|
||||
onComplete: (res) =>
|
||||
{
|
||||
Debug.Log("[PCHPTestExample] getSystemInfo 完成");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试事件监听
|
||||
/// </summary>
|
||||
[ContextMenu("Test Event Listener")]
|
||||
public void TestEventListener()
|
||||
{
|
||||
if (_pcManager == null || !_pcManager.IsSupported)
|
||||
{
|
||||
Debug.LogError("[PCHPTestExample] PC 高性能模式不可用");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[PCHPTestExample] 注册 onShow 事件监听...");
|
||||
|
||||
_pcManager.On("onShow", (data) =>
|
||||
{
|
||||
Debug.Log($"[PCHPTestExample] 收到 onShow 事件: {data}");
|
||||
});
|
||||
|
||||
_pcManager.On("onHide", (data) =>
|
||||
{
|
||||
Debug.Log($"[PCHPTestExample] 收到 onHide 事件: {data}");
|
||||
});
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
// 简单的测试按钮 UI
|
||||
GUILayout.BeginArea(new Rect(10, 10, 200, 300));
|
||||
GUILayout.Label("PC高性能小游戏测试");
|
||||
|
||||
if (GUILayout.Button("ShowToast"))
|
||||
{
|
||||
TestShowToast();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("ShowModal"))
|
||||
{
|
||||
TestShowModal();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("ShowLoading"))
|
||||
{
|
||||
TestShowLoading();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("GetSystemInfo"))
|
||||
{
|
||||
TestGenericAPICall();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Register Events"))
|
||||
{
|
||||
TestEventListener();
|
||||
}
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Runtime/Examples/PCHPTestExample.cs.meta
Normal file
7
Runtime/Examples/PCHPTestExample.cs.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ded19877eaa0ed06ad5a1d789d245ee
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59f30477a8bb77aeb6d56b69f0799388
|
||||
guid: 7eb6341fbacdfb6abbd4ac20932f16cd
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33778f932d74b9c0309d7573c86c9e5b
|
||||
guid: 8903e1fcd9b8806b128a853f763aedc1
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1195,8 +1195,38 @@ namespace WeChatWASM
|
||||
public static WXRankManager GetRankManager() {
|
||||
return WXSDKManagerHandler.Instance.GetRankManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PC高性能小游戏
|
||||
/// <summary>
|
||||
/// 获取 PC 高性能小游戏管理器
|
||||
/// 类似于 VA 方案的 wx.getAndroidHighPerformanceManager()
|
||||
/// 用于在 PC 原生环境下与微信基础库通信
|
||||
/// </summary>
|
||||
/// <returns>PC高性能管理器实例,如果不支持则返回 null</returns>
|
||||
/// <example>
|
||||
/// var pcManager = WX.GetPCHighPerformanceManager();
|
||||
/// if (pcManager != null && pcManager.IsSupported)
|
||||
/// {
|
||||
/// pcManager.ShowToast(new PCHPShowToastOption
|
||||
/// {
|
||||
/// title = "Hello PC!",
|
||||
/// icon = "success",
|
||||
/// duration = 2000
|
||||
/// });
|
||||
/// }
|
||||
/// </example>
|
||||
public static WXPCHighPerformanceManager GetPCHighPerformanceManager()
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
return WXPCHighPerformanceManager.GetInstance();
|
||||
#else
|
||||
Debug.LogWarning("[WX] GetPCHighPerformanceManager 仅在 Windows 平台可用");
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
972
Runtime/WXPCHPInitScript.cs
Normal file
972
Runtime/WXPCHPInitScript.cs
Normal file
@ -0,0 +1,972 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using LitJson;
|
||||
|
||||
namespace WeChatWASM
|
||||
{
|
||||
#region Message Protocol Models
|
||||
|
||||
/// <summary>
|
||||
/// PC高性能方案通信协议 - 请求消息
|
||||
/// C# -> DLL -> 内核 -> 基础库
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PCHPRequestMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息类型: "request" | "event_register" | "event_unregister"
|
||||
/// </summary>
|
||||
public string type;
|
||||
|
||||
/// <summary>
|
||||
/// 请求ID,用于匹配回调
|
||||
/// </summary>
|
||||
public string requestId;
|
||||
|
||||
/// <summary>
|
||||
/// API名称,如 "showToast", "login" 等
|
||||
/// </summary>
|
||||
public string api;
|
||||
|
||||
/// <summary>
|
||||
/// API参数,JSON格式
|
||||
/// </summary>
|
||||
public string data;
|
||||
|
||||
/// <summary>
|
||||
/// 时间戳
|
||||
/// </summary>
|
||||
public long timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PC高性能方案通信协议 - 响应消息
|
||||
/// 基础库 -> 内核 -> DLL -> C#
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PCHPResponseMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息类型: "response" | "event"
|
||||
/// </summary>
|
||||
public string type;
|
||||
|
||||
/// <summary>
|
||||
/// 请求ID,与请求消息匹配
|
||||
/// </summary>
|
||||
public string requestId;
|
||||
|
||||
/// <summary>
|
||||
/// 回调类型: "success" | "fail" | "complete"
|
||||
/// </summary>
|
||||
public string callbackType;
|
||||
|
||||
/// <summary>
|
||||
/// API名称(事件类型时使用)
|
||||
/// </summary>
|
||||
public string api;
|
||||
|
||||
/// <summary>
|
||||
/// 响应数据,JSON格式
|
||||
/// </summary>
|
||||
public string data;
|
||||
|
||||
/// <summary>
|
||||
/// 错误信息(失败时)
|
||||
/// </summary>
|
||||
public string errMsg;
|
||||
|
||||
/// <summary>
|
||||
/// 时间戳
|
||||
/// </summary>
|
||||
public long timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用回调结果
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PCHPGeneralCallbackResult
|
||||
{
|
||||
public string errMsg;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ShowToast 参数
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PCHPShowToastOption
|
||||
{
|
||||
public string title;
|
||||
public string icon;
|
||||
public string image;
|
||||
public int duration;
|
||||
public bool mask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ShowModal 参数
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PCHPShowModalOption
|
||||
{
|
||||
public string title;
|
||||
public string content;
|
||||
public bool showCancel;
|
||||
public string cancelText;
|
||||
public string cancelColor;
|
||||
public string confirmText;
|
||||
public string confirmColor;
|
||||
public bool editable;
|
||||
public string placeholderText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ShowModal 成功回调结果
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PCHPShowModalSuccessCallbackResult
|
||||
{
|
||||
public bool confirm;
|
||||
public bool cancel;
|
||||
public string content;
|
||||
public string errMsg;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// PC高性能小游戏初始化脚本
|
||||
/// 负责与宿主程序的 direct_applet_sdk.dll 进行交互
|
||||
/// </summary>
|
||||
public class WXPCHPInitScript : MonoBehaviour
|
||||
{
|
||||
#region DLL Imports
|
||||
|
||||
private const string DLL_NAME = "direct_applet_sdk.dll";
|
||||
|
||||
// 初始化SDK
|
||||
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool InitEmbeddedGameSDK();
|
||||
|
||||
// 注册异步消息处理器
|
||||
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void RegisterAsyncMsgHandler(AsyncMsgHandlerDelegate handler);
|
||||
|
||||
// 建立Mojo连接
|
||||
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool EstablishConnection();
|
||||
|
||||
// 初始化游戏窗口 - 传入窗口句柄
|
||||
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool InitGameWindow(ulong hwnd);
|
||||
|
||||
// 异步发送消息
|
||||
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool SendMsgAsync(IntPtr data, int len);
|
||||
|
||||
// 清理资源
|
||||
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool Cleanup();
|
||||
|
||||
// 获取当前活动窗口句柄
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr GetActiveWindow();
|
||||
|
||||
// Windows MessageBox
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delegate Definition
|
||||
|
||||
// 异步消息处理器委托
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void AsyncMsgHandlerDelegate(IntPtr data, int len);
|
||||
|
||||
// 保持委托引用,防止被GC回收
|
||||
private static AsyncMsgHandlerDelegate asyncMsgHandler;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Singleton
|
||||
|
||||
private static WXPCHPInitScript instance;
|
||||
public static WXPCHPInitScript Instance => instance;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Callback Management
|
||||
|
||||
/// <summary>
|
||||
/// 回调信息封装
|
||||
/// </summary>
|
||||
private class CallbackInfo
|
||||
{
|
||||
public Action<string> OnSuccess;
|
||||
public Action<string> OnFail;
|
||||
public Action<string> OnComplete;
|
||||
public string ApiName;
|
||||
public long Timestamp;
|
||||
}
|
||||
|
||||
// 待处理的回调字典 <requestId, CallbackInfo>
|
||||
private readonly Dictionary<string, CallbackInfo> _pendingCallbacks = new Dictionary<string, CallbackInfo>();
|
||||
|
||||
// 事件监听器字典 <eventName, List<Action<string>>>
|
||||
private readonly Dictionary<string, List<Action<string>>> _eventListeners = new Dictionary<string, List<Action<string>>>();
|
||||
|
||||
// 请求ID计数器
|
||||
private int _requestIdCounter = 0;
|
||||
|
||||
// 线程安全的消息队列,用于主线程处理
|
||||
private readonly ConcurrentQueue<PCHPResponseMessage> _messageQueue = new ConcurrentQueue<PCHPResponseMessage>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
// 收到异步消息时触发的事件(原始字节)
|
||||
public event Action<byte[]> OnMessageReceived;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
// SDK是否已初始化
|
||||
public bool IsInitialized { get; private set; }
|
||||
|
||||
// 是否已连接
|
||||
public bool IsConnected { get; private set; }
|
||||
|
||||
// 窗口句柄
|
||||
public IntPtr WindowHandle { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Lifecycle
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Debug.Log("[WXPCHPInitScript] ========== Awake 被调用 ==========");
|
||||
Debug.Log($"[WXPCHPInitScript] GameObject 名称: {gameObject.name}");
|
||||
Debug.Log($"[WXPCHPInitScript] 场景名称: {UnityEngine.SceneManagement.SceneManager.GetActiveScene().name}");
|
||||
|
||||
if (instance != null && instance != this)
|
||||
{
|
||||
Debug.LogWarning("[WXPCHPInitScript] 检测到重复实例,销毁当前对象");
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
Debug.Log("[WXPCHPInitScript] 单例创建成功,已设置 DontDestroyOnLoad");
|
||||
|
||||
// 初始化SDK
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 在主线程中处理消息队列
|
||||
ProcessMessageQueue();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (instance == this)
|
||||
{
|
||||
CleanupSDK();
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
CleanupSDK();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods - SDK Lifecycle
|
||||
|
||||
/// <summary>
|
||||
/// 初始化SDK并建立连接
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
if (IsInitialized)
|
||||
{
|
||||
Debug.LogWarning("[WXPCHPInitScript] SDK已经初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("[WXPCHPInitScript] ========== 开始初始化 ==========");
|
||||
Debug.Log($"[WXPCHPInitScript] 当前工作目录: {System.IO.Directory.GetCurrentDirectory()}");
|
||||
Debug.Log($"[WXPCHPInitScript] DLL 搜索路径: {DLL_NAME}");
|
||||
|
||||
ShowStepInfo("SDK 初始化开始", "即将执行 PC 高性能模式 SDK 初始化流程...\n\n共 5 个步骤:\n1. InitEmbeddedGameSDK\n2. RegisterAsyncMsgHandler\n3. EstablishConnection\n4. GetActiveWindow\n5. InitGameWindow");
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 初始化SDK
|
||||
Debug.Log("[WXPCHPInitScript] Step 1: 调用 InitEmbeddedGameSDK");
|
||||
ShowStepInfo("步骤 1/5 - InitEmbeddedGameSDK", "正在初始化嵌入式游戏 SDK...");
|
||||
if (!InitEmbeddedGameSDK())
|
||||
{
|
||||
ShowError("InitEmbeddedGameSDK 返回 false");
|
||||
return;
|
||||
}
|
||||
ShowStepInfo("步骤 1/5 - InitEmbeddedGameSDK ✅", "InitEmbeddedGameSDK 调用成功!");
|
||||
|
||||
// 2. 注册消息处理器
|
||||
Debug.Log("[WXPCHPInitScript] Step 2: 调用 RegisterAsyncMsgHandler");
|
||||
ShowStepInfo("步骤 2/5 - RegisterAsyncMsgHandler", "正在注册异步消息处理器...");
|
||||
asyncMsgHandler = HandleAsyncMessage;
|
||||
RegisterAsyncMsgHandler(asyncMsgHandler);
|
||||
ShowStepInfo("步骤 2/5 - RegisterAsyncMsgHandler ✅", "异步消息处理器注册成功!");
|
||||
|
||||
// 3. 建立连接
|
||||
Debug.Log("[WXPCHPInitScript] Step 3: 调用 EstablishConnection");
|
||||
ShowStepInfo("步骤 3/5 - EstablishConnection", "正在建立 Mojo 连接...");
|
||||
if (!EstablishConnection())
|
||||
{
|
||||
ShowError("EstablishConnection 返回 false");
|
||||
IsConnected = false;
|
||||
return;
|
||||
}
|
||||
IsConnected = true;
|
||||
ShowStepInfo("步骤 3/5 - EstablishConnection ✅", "Mojo 连接建立成功!");
|
||||
|
||||
// 4. 获取窗口句柄并初始化游戏窗口
|
||||
Debug.Log("[WXPCHPInitScript] Step 4: 获取窗口句柄");
|
||||
ShowStepInfo("步骤 4/5 - GetActiveWindow", "正在获取游戏窗口句柄...");
|
||||
WindowHandle = GetActiveWindow();
|
||||
if (WindowHandle == IntPtr.Zero)
|
||||
{
|
||||
ShowError("GetActiveWindow 返回空句柄");
|
||||
return;
|
||||
}
|
||||
Debug.Log($"获取窗口句柄成功: 0x{WindowHandle.ToInt64():X}");
|
||||
ShowStepInfo("步骤 4/5 - GetActiveWindow ✅", $"窗口句柄获取成功: 0x{WindowHandle.ToInt64():X}");
|
||||
|
||||
// 5. 通知内核获取窗口句柄
|
||||
Debug.Log("[WXPCHPInitScript] Step 5: 调用 InitGameWindow");
|
||||
ShowStepInfo("步骤 5/5 - InitGameWindow", $"正在初始化游戏窗口...\n窗口句柄: 0x{WindowHandle.ToInt64():X}");
|
||||
if (!InitGameWindow((ulong)WindowHandle.ToInt64()))
|
||||
{
|
||||
ShowError("InitGameWindow 返回 false");
|
||||
return;
|
||||
}
|
||||
ShowStepInfo("步骤 5/5 - InitGameWindow ✅", "游戏窗口初始化成功!");
|
||||
|
||||
IsInitialized = true;
|
||||
Debug.Log("[WXPCHPInitScript] ========== 初始化完成 ==========");
|
||||
ShowStepInfo("🎉 SDK 初始化完成", "PC 高性能模式 SDK 所有步骤均已成功完成!\n\n✅ InitEmbeddedGameSDK\n✅ RegisterAsyncMsgHandler\n✅ EstablishConnection\n✅ GetActiveWindow\n✅ InitGameWindow");
|
||||
}
|
||||
catch (DllNotFoundException e)
|
||||
{
|
||||
ShowError($"找不到DLL: {e.Message}\n\n请确保 {DLL_NAME} 在以下位置之一:\n- 与 .exe 同级目录\n- System32 目录\n- PATH 环境变量包含的路径");
|
||||
Debug.LogError($"[WXPCHPInitScript] DLL 加载失败,请确保 {DLL_NAME} 在以下位置之一:");
|
||||
Debug.LogError($" - 与 .exe 同级目录");
|
||||
Debug.LogError($" - System32 目录");
|
||||
Debug.LogError($" - PATH 环境变量包含的路径");
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
ShowError($"找不到函数入口: {e.Message}\n\n可能是 DLL 版本不匹配");
|
||||
Debug.LogError($"[WXPCHPInitScript] 函数入口点错误,可能是 DLL 版本不匹配");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ShowError($"初始化异常: {e.Message}\n{e.StackTrace}");
|
||||
Debug.LogError($"[WXPCHPInitScript] 未知异常: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods - WX API Calls
|
||||
|
||||
/// <summary>
|
||||
/// 调用微信API(通用方法)
|
||||
/// </summary>
|
||||
/// <param name="apiName">API名称,如 "showToast"</param>
|
||||
/// <param name="data">API参数对象</param>
|
||||
/// <param name="onSuccess">成功回调</param>
|
||||
/// <param name="onFail">失败回调</param>
|
||||
/// <param name="onComplete">完成回调</param>
|
||||
/// <returns>请求ID</returns>
|
||||
public string CallWXAPI(string apiName, object data, Action<string> onSuccess = null, Action<string> onFail = null, Action<string> onComplete = null)
|
||||
{
|
||||
if (!IsInitialized || !IsConnected)
|
||||
{
|
||||
Debug.LogWarning($"[WXPCHPInitScript] SDK未初始化或未连接,无法调用 {apiName}");
|
||||
onFail?.Invoke(JsonMapper.ToJson(new PCHPGeneralCallbackResult { errMsg = "SDK not initialized" }));
|
||||
onComplete?.Invoke(JsonMapper.ToJson(new PCHPGeneralCallbackResult { errMsg = "SDK not initialized" }));
|
||||
return null;
|
||||
}
|
||||
|
||||
string requestId = GenerateRequestId();
|
||||
string dataJson = data != null ? JsonMapper.ToJson(data) : "{}";
|
||||
|
||||
// 注册回调
|
||||
var callbackInfo = new CallbackInfo
|
||||
{
|
||||
OnSuccess = onSuccess,
|
||||
OnFail = onFail,
|
||||
OnComplete = onComplete,
|
||||
ApiName = apiName,
|
||||
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
||||
};
|
||||
_pendingCallbacks[requestId] = callbackInfo;
|
||||
|
||||
// 构建请求消息
|
||||
var request = new PCHPRequestMessage
|
||||
{
|
||||
type = "request",
|
||||
requestId = requestId,
|
||||
api = apiName,
|
||||
data = dataJson,
|
||||
timestamp = callbackInfo.Timestamp
|
||||
};
|
||||
|
||||
string requestJson = JsonMapper.ToJson(request);
|
||||
Debug.Log($"[WXPCHPInitScript] 发送API请求: {apiName}, requestId: {requestId}");
|
||||
|
||||
if (!SendMessageInternal(requestJson))
|
||||
{
|
||||
_pendingCallbacks.Remove(requestId);
|
||||
onFail?.Invoke(JsonMapper.ToJson(new PCHPGeneralCallbackResult { errMsg = "Failed to send message" }));
|
||||
onComplete?.Invoke(JsonMapper.ToJson(new PCHPGeneralCallbackResult { errMsg = "Failed to send message" }));
|
||||
return null;
|
||||
}
|
||||
|
||||
return requestId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示消息提示框
|
||||
/// </summary>
|
||||
public void ShowToast(PCHPShowToastOption option, Action<PCHPGeneralCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
CallWXAPI("showToast", option,
|
||||
res => success?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => fail?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => complete?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏消息提示框
|
||||
/// </summary>
|
||||
public void HideToast(Action<PCHPGeneralCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
CallWXAPI("hideToast", null,
|
||||
res => success?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => fail?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => complete?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示模态对话框
|
||||
/// </summary>
|
||||
public void ShowModal(PCHPShowModalOption option, Action<PCHPShowModalSuccessCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
CallWXAPI("showModal", option,
|
||||
res => success?.Invoke(JsonMapper.ToObject<PCHPShowModalSuccessCallbackResult>(res)),
|
||||
res => fail?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => complete?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示 loading 提示框
|
||||
/// </summary>
|
||||
public void ShowLoading(string title, bool mask = false, Action<PCHPGeneralCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
CallWXAPI("showLoading", new { title, mask },
|
||||
res => success?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => fail?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => complete?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏 loading 提示框
|
||||
/// </summary>
|
||||
public void HideLoading(Action<PCHPGeneralCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
CallWXAPI("hideLoading", null,
|
||||
res => success?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => fail?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res)),
|
||||
res => complete?.Invoke(JsonMapper.ToObject<PCHPGeneralCallbackResult>(res))
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods - Event Listeners
|
||||
|
||||
/// <summary>
|
||||
/// 注册事件监听器
|
||||
/// </summary>
|
||||
/// <param name="eventName">事件名称,如 "onShow", "onHide"</param>
|
||||
/// <param name="callback">回调函数</param>
|
||||
public void RegisterEventListener(string eventName, Action<string> callback)
|
||||
{
|
||||
if (!_eventListeners.ContainsKey(eventName))
|
||||
{
|
||||
_eventListeners[eventName] = new List<Action<string>>();
|
||||
|
||||
// 发送事件注册消息到基础库
|
||||
var request = new PCHPRequestMessage
|
||||
{
|
||||
type = "event_register",
|
||||
requestId = GenerateRequestId(),
|
||||
api = eventName,
|
||||
data = "{}",
|
||||
timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
||||
};
|
||||
SendMessageInternal(JsonMapper.ToJson(request));
|
||||
}
|
||||
|
||||
_eventListeners[eventName].Add(callback);
|
||||
Debug.Log($"[WXPCHPInitScript] 注册事件监听: {eventName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除事件监听器
|
||||
/// </summary>
|
||||
/// <param name="eventName">事件名称</param>
|
||||
/// <param name="callback">要移除的回调函数,为null则移除所有</param>
|
||||
public void UnregisterEventListener(string eventName, Action<string> callback = null)
|
||||
{
|
||||
if (!_eventListeners.ContainsKey(eventName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback == null)
|
||||
{
|
||||
_eventListeners.Remove(eventName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_eventListeners[eventName].Remove(callback);
|
||||
if (_eventListeners[eventName].Count == 0)
|
||||
{
|
||||
_eventListeners.Remove(eventName);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有监听器了,通知基础库取消注册
|
||||
if (!_eventListeners.ContainsKey(eventName))
|
||||
{
|
||||
var request = new PCHPRequestMessage
|
||||
{
|
||||
type = "event_unregister",
|
||||
requestId = GenerateRequestId(),
|
||||
api = eventName,
|
||||
data = "{}",
|
||||
timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
||||
};
|
||||
SendMessageInternal(JsonMapper.ToJson(request));
|
||||
}
|
||||
|
||||
Debug.Log($"[WXPCHPInitScript] 移除事件监听: {eventName}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods - Raw Message
|
||||
|
||||
/// <summary>
|
||||
/// 发送原始消息字符串
|
||||
/// </summary>
|
||||
/// <param name="message">消息内容</param>
|
||||
/// <returns>是否发送成功</returns>
|
||||
public bool SendRawMessage(string message)
|
||||
{
|
||||
return SendMessageInternal(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送原始消息字节数组
|
||||
/// </summary>
|
||||
/// <param name="data">消息数据</param>
|
||||
/// <returns>是否发送成功</returns>
|
||||
public bool SendMessage(byte[] data)
|
||||
{
|
||||
if (!IsInitialized || !IsConnected)
|
||||
{
|
||||
Debug.LogWarning("[WXPCHPInitScript] SDK未初始化或未连接");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data == null || data.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("[WXPCHPInitScript] 发送的数据为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IntPtr ptr = Marshal.AllocHGlobal(data.Length);
|
||||
try
|
||||
{
|
||||
Marshal.Copy(data, 0, ptr, data.Length);
|
||||
return SendMsgAsync(ptr, data.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[WXPCHPInitScript] 发送消息异常: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// 生成唯一请求ID
|
||||
/// </summary>
|
||||
private string GenerateRequestId()
|
||||
{
|
||||
return $"pchp_{++_requestIdCounter}_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内部发送消息方法
|
||||
/// </summary>
|
||||
private bool SendMessageInternal(string message)
|
||||
{
|
||||
if (!IsInitialized || !IsConnected)
|
||||
{
|
||||
Debug.LogWarning("[WXPCHPInitScript] SDK未初始化或未连接");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
|
||||
return SendMessage(data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[WXPCHPInitScript] 发送消息异常: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示步骤信息弹窗(Windows 使用 MessageBox,其他平台使用 Debug.Log)
|
||||
/// </summary>
|
||||
private void ShowStepInfo(string title, string message)
|
||||
{
|
||||
Debug.Log($"[WXPCHPInitScript] [{title}] {message}");
|
||||
#if UNITY_STANDALONE_WIN
|
||||
try
|
||||
{
|
||||
// MB_OK | MB_ICONINFORMATION = 0x40
|
||||
MessageBox(IntPtr.Zero, message, $"PC高性能模式 - {title}", 0x40);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[WXPCHPInitScript] MessageBox 调用失败: {e.Message}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示错误弹窗(仅 Windows)
|
||||
/// </summary>
|
||||
private void ShowError(string message)
|
||||
{
|
||||
Debug.LogError($"[WXPCHPInitScript] {message}");
|
||||
#if UNITY_STANDALONE_WIN
|
||||
try
|
||||
{
|
||||
// MB_OK | MB_ICONERROR = 0x10
|
||||
MessageBox(IntPtr.Zero, message, "WXPCHPInitScript Error", 0x10);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[WXPCHPInitScript] MessageBox 调用失败: {e.Message}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理SDK资源
|
||||
/// </summary>
|
||||
private void CleanupSDK()
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 清理待处理回调
|
||||
_pendingCallbacks.Clear();
|
||||
_eventListeners.Clear();
|
||||
|
||||
Cleanup();
|
||||
Debug.Log("[WXPCHPInitScript] SDK清理完成");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[WXPCHPInitScript] 清理异常: {e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsInitialized = false;
|
||||
IsConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在主线程中处理消息队列
|
||||
/// </summary>
|
||||
private void ProcessMessageQueue()
|
||||
{
|
||||
while (_messageQueue.TryDequeue(out var response))
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessResponse(response);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[WXPCHPInitScript] 处理响应消息异常: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理响应消息
|
||||
/// </summary>
|
||||
private void ProcessResponse(PCHPResponseMessage response)
|
||||
{
|
||||
if (response.type == "response")
|
||||
{
|
||||
// 处理API回调
|
||||
if (_pendingCallbacks.TryGetValue(response.requestId, out var callbackInfo))
|
||||
{
|
||||
Debug.Log($"[WXPCHPInitScript] 收到API响应: {callbackInfo.ApiName}, callbackType: {response.callbackType}");
|
||||
|
||||
switch (response.callbackType)
|
||||
{
|
||||
case "success":
|
||||
callbackInfo.OnSuccess?.Invoke(response.data ?? "{}");
|
||||
break;
|
||||
case "fail":
|
||||
callbackInfo.OnFail?.Invoke(response.data ?? $"{{\"errMsg\":\"{response.errMsg}\"}}");
|
||||
break;
|
||||
case "complete":
|
||||
callbackInfo.OnComplete?.Invoke(response.data ?? "{}");
|
||||
// complete 后移除回调
|
||||
_pendingCallbacks.Remove(response.requestId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[WXPCHPInitScript] 未找到对应的回调: requestId={response.requestId}");
|
||||
}
|
||||
}
|
||||
else if (response.type == "event")
|
||||
{
|
||||
// 处理事件通知
|
||||
string eventName = response.api;
|
||||
if (_eventListeners.TryGetValue(eventName, out var listeners))
|
||||
{
|
||||
Debug.Log($"[WXPCHPInitScript] 收到事件: {eventName}");
|
||||
foreach (var listener in listeners.ToArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
listener?.Invoke(response.data ?? "{}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[WXPCHPInitScript] 事件回调异常: {eventName}, {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步消息处理回调(从DLL回调,可能在非主线程)
|
||||
/// </summary>
|
||||
[AOT.MonoPInvokeCallback(typeof(AsyncMsgHandlerDelegate))]
|
||||
private static void HandleAsyncMessage(IntPtr data, int len)
|
||||
{
|
||||
if (data == IntPtr.Zero || len <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
byte[] buffer = new byte[len];
|
||||
Marshal.Copy(data, buffer, 0, len);
|
||||
|
||||
if (instance != null)
|
||||
{
|
||||
// 触发原始消息事件
|
||||
instance.OnMessageReceived?.Invoke(buffer);
|
||||
|
||||
// 解析消息
|
||||
string message = System.Text.Encoding.UTF8.GetString(buffer);
|
||||
Debug.Log($"[WXPCHPInitScript] 收到原始消息: {message}");
|
||||
|
||||
try
|
||||
{
|
||||
// 尝试解析为响应消息
|
||||
var response = JsonMapper.ToObject<PCHPResponseMessage>(message);
|
||||
if (response != null && !string.IsNullOrEmpty(response.type))
|
||||
{
|
||||
// 加入消息队列,在主线程中处理
|
||||
instance._messageQueue.Enqueue(response);
|
||||
}
|
||||
}
|
||||
catch (Exception parseEx)
|
||||
{
|
||||
Debug.LogWarning($"[WXPCHPInitScript] 消息解析失败,可能是非标准格式: {parseEx.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[WXPCHPInitScript] 处理消息异常: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PC高性能小游戏管理器
|
||||
/// 提供类似 wx.getPCHighPerformanceManager() 的接口
|
||||
/// </summary>
|
||||
public class WXPCHighPerformanceManager
|
||||
{
|
||||
private static WXPCHighPerformanceManager _instance;
|
||||
private WXPCHPInitScript _initScript;
|
||||
|
||||
/// <summary>
|
||||
/// 获取 PC 高性能管理器实例
|
||||
/// </summary>
|
||||
public static WXPCHighPerformanceManager GetInstance()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new WXPCHighPerformanceManager();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
private WXPCHighPerformanceManager()
|
||||
{
|
||||
_initScript = WXPCHPInitScript.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持PC高性能模式
|
||||
/// </summary>
|
||||
public bool IsSupported => _initScript != null && _initScript.IsInitialized && _initScript.IsConnected;
|
||||
|
||||
/// <summary>
|
||||
/// 调用微信API
|
||||
/// </summary>
|
||||
public string CallWXAPI(string apiName, object data, Action<string> onSuccess = null, Action<string> onFail = null, Action<string> onComplete = null)
|
||||
{
|
||||
if (_initScript == null)
|
||||
{
|
||||
Debug.LogError("[WXPCHighPerformanceManager] InitScript 未初始化");
|
||||
return null;
|
||||
}
|
||||
return _initScript.CallWXAPI(apiName, data, onSuccess, onFail, onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示 Toast
|
||||
/// </summary>
|
||||
public void ShowToast(PCHPShowToastOption option, Action<PCHPGeneralCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
_initScript?.ShowToast(option, success, fail, complete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏 Toast
|
||||
/// </summary>
|
||||
public void HideToast(Action<PCHPGeneralCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
_initScript?.HideToast(success, fail, complete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示模态对话框
|
||||
/// </summary>
|
||||
public void ShowModal(PCHPShowModalOption option, Action<PCHPShowModalSuccessCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
_initScript?.ShowModal(option, success, fail, complete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示 Loading
|
||||
/// </summary>
|
||||
public void ShowLoading(string title, bool mask = false, Action<PCHPGeneralCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
_initScript?.ShowLoading(title, mask, success, fail, complete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏 Loading
|
||||
/// </summary>
|
||||
public void HideLoading(Action<PCHPGeneralCallbackResult> success = null, Action<PCHPGeneralCallbackResult> fail = null, Action<PCHPGeneralCallbackResult> complete = null)
|
||||
{
|
||||
_initScript?.HideLoading(success, fail, complete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册事件监听
|
||||
/// </summary>
|
||||
public void On(string eventName, Action<string> callback)
|
||||
{
|
||||
_initScript?.RegisterEventListener(eventName, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除事件监听
|
||||
/// </summary>
|
||||
public void Off(string eventName, Action<string> callback = null)
|
||||
{
|
||||
_initScript?.UnregisterEventListener(eventName, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送原始消息
|
||||
/// </summary>
|
||||
public bool SendRawMessage(string message)
|
||||
{
|
||||
return _initScript?.SendRawMessage(message) ?? false;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Runtime/WXPCHPInitScript.cs.meta
Normal file
7
Runtime/WXPCHPInitScript.cs.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65b48177033749bf973a8af5bfb6b257
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3d5d2167fc6b91f7fa3e08ea84c3cda
|
||||
guid: 28899446f92813abc017215ece09564b
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c06693e00be3ab1fde2607590ab4e6d
|
||||
guid: aa1d5b30a1d9014052f11cad2670393e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a02513af1cc852341848d1ee2622c3aa
|
||||
guid: 56560c181a50b6ed69dbce5f841a46ee
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de11e750d070e1521430f1ea7d7e9b10
|
||||
guid: cd9d2a4b822b2a6e9e9cad875b78d30e
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75c495849e8b58894c4df4019c28990f
|
||||
guid: b78fadb0d56d2651cce08e4d0a1d7b8b
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2676c806e8720f27b3c91d7b88934aea
|
||||
guid: ca563ce4e3d50d40250ace95cf4d2b5a
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f98ab3c051a738848f5f25b3963ff875
|
||||
guid: 6e3e482927dfab693668a487c92625df
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14b4dacf147a2eb0b690def4fd2a25f8
|
||||
guid: 140e14eadf2ba97e573fb02804b4908e
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdc5a07bfe255668c4bc90b063ab0439
|
||||
guid: ea4fc096af9a7cc258be6de28299cc10
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc12ac5f1dcfb4041e5b88bdb3d39df1
|
||||
guid: 77d410f576a4c99b91ee1eaa4ec9ed6b
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a78826b373fd69d30b14736655164fc
|
||||
guid: 8c0de764e7412cdac5ac442449b57c4c
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e3a00c4051da2b6217cd8e156b32adc
|
||||
guid: c63edd3a8984af6f437d335d4da6d55b
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa4490b63d04c3666e7d5bd6dbbe4a58
|
||||
guid: 62d7d82e71575079d903119515b7e02b
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 942f7b8a85c48dce854289ad244f3ca4
|
||||
guid: 3b69d1bf725f2a5b22174676c711bdfb
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4dadbfddf470bde3a646527500a79bb6
|
||||
guid: 7ffc8f045e80e93dcf8421ceccdd2286
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1516197a3756cc06853320f648bd30f2
|
||||
guid: ad8fdb60f01b5dc2bee092b99c69bc53
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b193152a2bbc37d0feda3c6544e7afc8
|
||||
guid: a01044e15755b708d9152afeb5b99af2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5a694336b7dd91fd242250f890f19b5
|
||||
guid: 4611d918af0c2abf544919b91c34c24a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f862d1c69deabf4048bebed751c846d
|
||||
guid: f93674309736b866b67fce195487754f
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7eb49c157fec3510cca59918268546d6
|
||||
guid: 5dcbc4a169b3678d94199c6e3c69b023
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6eb3ae66cc21f0114a7c9e15ac57d76
|
||||
guid: d8851e8edd336d9adc7ea544668daefb
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1151cf42fe9e3fe2b444ddddbde08396
|
||||
guid: 523efb46f09536abea4b253fe4597b61
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b6db07c37dc2366237d59d8f785fd48
|
||||
guid: 86b43213e9f94d8022cd863f7f154517
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e2b29c063f2d000be5dd2313958fa6c
|
||||
guid: 70707c20b429a5ad0bb9758ef9c4ee88
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d34cf0ce316d07409a850c605540a013
|
||||
guid: 878874b37e27c8785c5b4215032c0e4c
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d91ef4c43c9f3c9a6da9a65b379b5740
|
||||
guid: ee8906ec10a506f89e2e595854b6ed95
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6660a6a8aacee1f2096340441fdbd3ce
|
||||
guid: 1b28f3de84eebf692b06882e12ca107e
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 119c8bb6b0ad127ed8bac3162a9969f8
|
||||
guid: 2d4a6b0ae9e133566ffbe634063068b4
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59d869d78f133094896b88faa762234a
|
||||
guid: 6e50143d925c2d3bccb04bd306874aca
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34d39008817c30ca826af31fc01525e7
|
||||
guid: d6830ecbe3ebd9fc7c99628994e2109b
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73a18f6a646fbaf0e8526fc1526ae97a
|
||||
guid: 810022c3291e27903e54afe0c3ed356c
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9e4678df01d9876b1b0aa336ee45401
|
||||
guid: bc6d35876a1df184808fcf7ea16299f1
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2c849f6ee1aeeb7f9ccc36695a38d24
|
||||
guid: 986ac1ae35cec7469862f9d6a70545dd
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2200a16cb9b949081f51aa4fe6807bd
|
||||
guid: 7903401c90fdd999396fddef97b0c5b4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b89e0228f0375beca9b6d7b1ad95356a
|
||||
guid: 20932608b374aead69eef9dfd15276b4
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c82e223e59fd93811d3aa303bb51f02e
|
||||
guid: 9d66cf62d960c22a50c3608e8722391d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c570e4eb7ff538d7aa640fb8c3d02da
|
||||
guid: f7d6d428f44cb4f9017753e54c8792d4
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a8702f6acee306755d112480d39813c
|
||||
guid: 3c2dddbf9d3aabbed6d42b974d235a43
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90a536e2c5a0814cc1c58b70c92da9a4
|
||||
guid: 916440cf074e747848cb654d14f13861
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02830b8246e010bdd89e47fefd9adf6b
|
||||
guid: ba5c8a70265edd293a0bbc1bca8e1f23
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 853f4640fa1b8a092c4ccb4669d6971c
|
||||
guid: 5a047f6985037ff4af2f0216cae1e0d0
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24c205c5759ec41da1b00eda2ac42564
|
||||
guid: edb36dedb719e633c52aab7b5f8fa6fd
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9782628a70978396e495b86274aa398d
|
||||
guid: 0f10a9296a26f6b141050605f16db459
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 674bba89e7bc0b330d4920c8a1d2470f
|
||||
guid: 395f3f8506fbde9f2d9595a862c0debb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: faa496c26f840b60f61ac89b5f564f32
|
||||
guid: 90ae68d3704fdb72ab4e9f0fd382f475
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6cbac21da9894d5092f47042e7dcab8e
|
||||
guid: a7933293bdabc5401eb78c5c2a67c2d2
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa534e5bd9009a4f986abd6cc2ff823b
|
||||
guid: 10cd9eebf96f177c39cd69b560cea12d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3251c8f50cca5fae20e0e2bbc567bf40
|
||||
guid: ae717fecd969ec6df4155595fb026b75
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ee130afc0339063c59da8a830c7663e
|
||||
guid: 063167dda766bb04e0e86aac07d043ae
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30161526e5960c70e6965463a8c98492
|
||||
guid: 3d7597262408e2f20b02f5a1bff34903
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47d2bb9aac0b87cfdf12358dc192e755
|
||||
guid: cf20302275f0146493a7fe14f657decd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7babfccd3322d8f0bb49bb466cc03624
|
||||
guid: d5b52d5802ad2bccc888949cf66982e0
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a99dd0e69496ec987fc46d387fee8587
|
||||
guid: 5a7e11087cbf87e802659b3456593e3f
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: deb969752e56efd1f30292483076fe8d
|
||||
guid: 252e8a34c210937fd548bad299010393
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 873c3ff5c09c499cea533e76613b289c
|
||||
guid: 0b55a20502c5a31cf83c607b8d02c793
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b62dfcd3bba0143fe64bb393b6718200
|
||||
guid: 92c6b0ea472825b3c96bc55b97759662
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f5d268ad00ae324c34a888a2bc0f3b9
|
||||
guid: 083c7cc77d88b5ea17946429df108415
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4b7634dc3628a25ae87b92a174f5056
|
||||
guid: ddb5b594a8c36b4d6aa282b1642b3115
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acc81d1c264bc0dadd4552d59e6b5cc0
|
||||
guid: b69b9c95a5eaee75b990748fb3349fe1
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 304fa8442a722ea29aaf75c80ecf36d0
|
||||
guid: 88c9729d66da5e03f0d986dfcfcbaac2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07577f5e35b0d9d10be3e7da2f636244
|
||||
guid: 61e3864b146a15bd1001edb987600f68
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90f5231878ca8f4be00b3ce66b678dd1
|
||||
guid: da519d291f45321de3669a9c2242ae7d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f54994eb4369a71edd1d509002ad2f14
|
||||
guid: f04169480cf692873309cef1f4b0a6c8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48fbcdad3f9d3b9f921019659939b17c
|
||||
guid: fd3034a9e5d848643c9b02c1caef7699
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 116976e02bc785ec509b059f15a5826b
|
||||
guid: 38c1a3295ec3820866efeb892a9f3aac
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39b854a719f26a74ceafd3208b3d1559
|
||||
guid: 67459c98836cb4524ce79af7c167b045
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71c319aa5539d8cc938c59c1f95015a2
|
||||
guid: 73c83bec8fece5a1ecdffcf03ffbe742
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c4cd8fe6d78dca85ddf042297dbfa8e
|
||||
guid: 29747fb536135bf9897bbb87d1cb1bc8
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user