Auto-publish.

This commit is contained in:
nebulaliu 2026-03-25 11:24:23 +08:00
parent f67e7851c3
commit d37d6d8608
191 changed files with 3137 additions and 166 deletions

View File

@ -6,7 +6,7 @@ Removed - 删除功能/接口
Fixed - 修复问题
Others - 其他
-->
## 2026-3-15 v0.1.32 【普通更新】
## 2026-3-16 v0.1.32 【普通更新】
### Feature
* 普通:更新基础库版本
* 普通擂台赛api新增subScoreKey参数

View 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);
}
}
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b2764f66c7a7ee9dfaf53ffe5f6215d0
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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 构建

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: aacc596790ffe1aad08acb624adcdfaa
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,152 @@
# PC高性能小游戏 - 问题排查指南
## 🐛 问题1设置面板数据被清空
### 原因
`OnLostFocus()` 时机不对,输入框的值可能还未同步到 `formInputData`
### 解决方案 ✅
已修复:在 `OnSettingsGUI()` 中添加 `GUI.changed` 检测,每次输入时自动保存
---
## 🐛 问题2ShowInfo 逻辑未执行
### 可能原因
#### 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 设置 |

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8b57398b893716f5822f5e196466fee6
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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));
}
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c5e90582a5951eff22c3b110229de415
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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>
/// 恢复到小游戏平台
/// 团结引擎使用 WeixinMiniGameUnity 使用 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, VulkanLinear 色彩空间兼容)");
}
else
{
// Gamma 色彩空间,使用默认图形 API 即可
PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.StandaloneWindows64, true);
Debug.Log("[PC高性能模式] 使用默认 Windows 图形 APIGamma 色彩空间)");
}
}
/// <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();
}
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1455a91f4635862b70423ea92eff07bb
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1f0df5132a2e6c4a2e5541e3472a6422
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 769878c6cc6489f59f3bca6835614c27
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}

View File

@ -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");

View File

@ -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.

View File

@ -493,6 +493,11 @@
注意不要随意修改默认值为00表示不限制
</summary>
</member>
<member name="F:WeChatWASM.WXProjectConf.EnablePCHighPerformance">
<summary>
是否开启PC高性能模式
</summary>
</member>
<member name="F:WeChatWASM.CompressTexture.halfSize">
<summary>
自动将图片尺寸减小一半

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7330c57dbe403f6a6825fe311f4436ca
guid: fc63c7c713805714b1dd0992ae9dcff2
DefaultImporter:
externalObjects: {}
userData:

8
Runtime/Examples.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b8fdca948fd6a64887c0534f384f283f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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] 当前平台非 WindowsPC 高性能模式不可用");
#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();
}
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0ded19877eaa0ed06ad5a1d789d245ee
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 59f30477a8bb77aeb6d56b69f0799388
guid: 7eb6341fbacdfb6abbd4ac20932f16cd
DefaultImporter:
externalObjects: {}
userData:

Binary file not shown.

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 33778f932d74b9c0309d7573c86c9e5b
guid: 8903e1fcd9b8806b128a853f763aedc1
DefaultImporter:
externalObjects: {}
userData:

View File

@ -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
View 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;
}
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 65b48177033749bf973a8af5bfb6b257
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d3d5d2167fc6b91f7fa3e08ea84c3cda
guid: 28899446f92813abc017215ece09564b
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6c06693e00be3ab1fde2607590ab4e6d
guid: aa1d5b30a1d9014052f11cad2670393e
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a02513af1cc852341848d1ee2622c3aa
guid: 56560c181a50b6ed69dbce5f841a46ee
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: de11e750d070e1521430f1ea7d7e9b10
guid: cd9d2a4b822b2a6e9e9cad875b78d30e
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 75c495849e8b58894c4df4019c28990f
guid: b78fadb0d56d2651cce08e4d0a1d7b8b
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 2676c806e8720f27b3c91d7b88934aea
guid: ca563ce4e3d50d40250ace95cf4d2b5a
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: f98ab3c051a738848f5f25b3963ff875
guid: 6e3e482927dfab693668a487c92625df
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 14b4dacf147a2eb0b690def4fd2a25f8
guid: 140e14eadf2ba97e573fb02804b4908e
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: fdc5a07bfe255668c4bc90b063ab0439
guid: ea4fc096af9a7cc258be6de28299cc10
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: cc12ac5f1dcfb4041e5b88bdb3d39df1
guid: 77d410f576a4c99b91ee1eaa4ec9ed6b
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3a78826b373fd69d30b14736655164fc
guid: 8c0de764e7412cdac5ac442449b57c4c
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7e3a00c4051da2b6217cd8e156b32adc
guid: c63edd3a8984af6f437d335d4da6d55b
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: fa4490b63d04c3666e7d5bd6dbbe4a58
guid: 62d7d82e71575079d903119515b7e02b
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 942f7b8a85c48dce854289ad244f3ca4
guid: 3b69d1bf725f2a5b22174676c711bdfb
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 4dadbfddf470bde3a646527500a79bb6
guid: 7ffc8f045e80e93dcf8421ceccdd2286
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 1516197a3756cc06853320f648bd30f2
guid: ad8fdb60f01b5dc2bee092b99c69bc53
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b193152a2bbc37d0feda3c6544e7afc8
guid: a01044e15755b708d9152afeb5b99af2
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b5a694336b7dd91fd242250f890f19b5
guid: 4611d918af0c2abf544919b91c34c24a
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 5f862d1c69deabf4048bebed751c846d
guid: f93674309736b866b67fce195487754f
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7eb49c157fec3510cca59918268546d6
guid: 5dcbc4a169b3678d94199c6e3c69b023
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: f6eb3ae66cc21f0114a7c9e15ac57d76
guid: d8851e8edd336d9adc7ea544668daefb
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 1151cf42fe9e3fe2b444ddddbde08396
guid: 523efb46f09536abea4b253fe4597b61
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 2b6db07c37dc2366237d59d8f785fd48
guid: 86b43213e9f94d8022cd863f7f154517
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 0e2b29c063f2d000be5dd2313958fa6c
guid: 70707c20b429a5ad0bb9758ef9c4ee88
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d34cf0ce316d07409a850c605540a013
guid: 878874b37e27c8785c5b4215032c0e4c
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d91ef4c43c9f3c9a6da9a65b379b5740
guid: ee8906ec10a506f89e2e595854b6ed95
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6660a6a8aacee1f2096340441fdbd3ce
guid: 1b28f3de84eebf692b06882e12ca107e
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 119c8bb6b0ad127ed8bac3162a9969f8
guid: 2d4a6b0ae9e133566ffbe634063068b4
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 59d869d78f133094896b88faa762234a
guid: 6e50143d925c2d3bccb04bd306874aca
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 34d39008817c30ca826af31fc01525e7
guid: d6830ecbe3ebd9fc7c99628994e2109b
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 73a18f6a646fbaf0e8526fc1526ae97a
guid: 810022c3291e27903e54afe0c3ed356c
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c9e4678df01d9876b1b0aa336ee45401
guid: bc6d35876a1df184808fcf7ea16299f1
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c2c849f6ee1aeeb7f9ccc36695a38d24
guid: 986ac1ae35cec7469862f9d6a70545dd
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b2200a16cb9b949081f51aa4fe6807bd
guid: 7903401c90fdd999396fddef97b0c5b4
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b89e0228f0375beca9b6d7b1ad95356a
guid: 20932608b374aead69eef9dfd15276b4
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c82e223e59fd93811d3aa303bb51f02e
guid: 9d66cf62d960c22a50c3608e8722391d
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3c570e4eb7ff538d7aa640fb8c3d02da
guid: f7d6d428f44cb4f9017753e54c8792d4
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 9a8702f6acee306755d112480d39813c
guid: 3c2dddbf9d3aabbed6d42b974d235a43
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 90a536e2c5a0814cc1c58b70c92da9a4
guid: 916440cf074e747848cb654d14f13861
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 02830b8246e010bdd89e47fefd9adf6b
guid: ba5c8a70265edd293a0bbc1bca8e1f23
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 853f4640fa1b8a092c4ccb4669d6971c
guid: 5a047f6985037ff4af2f0216cae1e0d0
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 24c205c5759ec41da1b00eda2ac42564
guid: edb36dedb719e633c52aab7b5f8fa6fd
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 9782628a70978396e495b86274aa398d
guid: 0f10a9296a26f6b141050605f16db459
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 674bba89e7bc0b330d4920c8a1d2470f
guid: 395f3f8506fbde9f2d9595a862c0debb
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: faa496c26f840b60f61ac89b5f564f32
guid: 90ae68d3704fdb72ab4e9f0fd382f475
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6cbac21da9894d5092f47042e7dcab8e
guid: a7933293bdabc5401eb78c5c2a67c2d2
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: aa534e5bd9009a4f986abd6cc2ff823b
guid: 10cd9eebf96f177c39cd69b560cea12d
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3251c8f50cca5fae20e0e2bbc567bf40
guid: ae717fecd969ec6df4155595fb026b75
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6ee130afc0339063c59da8a830c7663e
guid: 063167dda766bb04e0e86aac07d043ae
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 30161526e5960c70e6965463a8c98492
guid: 3d7597262408e2f20b02f5a1bff34903
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 47d2bb9aac0b87cfdf12358dc192e755
guid: cf20302275f0146493a7fe14f657decd
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7babfccd3322d8f0bb49bb466cc03624
guid: d5b52d5802ad2bccc888949cf66982e0
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a99dd0e69496ec987fc46d387fee8587
guid: 5a7e11087cbf87e802659b3456593e3f
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: deb969752e56efd1f30292483076fe8d
guid: 252e8a34c210937fd548bad299010393
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 873c3ff5c09c499cea533e76613b289c
guid: 0b55a20502c5a31cf83c607b8d02c793
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b62dfcd3bba0143fe64bb393b6718200
guid: 92c6b0ea472825b3c96bc55b97759662
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 0f5d268ad00ae324c34a888a2bc0f3b9
guid: 083c7cc77d88b5ea17946429df108415
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c4b7634dc3628a25ae87b92a174f5056
guid: ddb5b594a8c36b4d6aa282b1642b3115
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: acc81d1c264bc0dadd4552d59e6b5cc0
guid: b69b9c95a5eaee75b990748fb3349fe1
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 304fa8442a722ea29aaf75c80ecf36d0
guid: 88c9729d66da5e03f0d986dfcfcbaac2
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 07577f5e35b0d9d10be3e7da2f636244
guid: 61e3864b146a15bd1001edb987600f68
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 90f5231878ca8f4be00b3ce66b678dd1
guid: da519d291f45321de3669a9c2242ae7d
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: f54994eb4369a71edd1d509002ad2f14
guid: f04169480cf692873309cef1f4b0a6c8
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 48fbcdad3f9d3b9f921019659939b17c
guid: fd3034a9e5d848643c9b02c1caef7699
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 116976e02bc785ec509b059f15a5826b
guid: 38c1a3295ec3820866efeb892a9f3aac
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 39b854a719f26a74ceafd3208b3d1559
guid: 67459c98836cb4524ce79af7c167b045
DefaultImporter:
externalObjects: {}
userData:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 71c319aa5539d8cc938c59c1f95015a2
guid: 73c83bec8fece5a1ecdffcf03ffbe742
DefaultImporter:
externalObjects: {}
userData:

View File

@ -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