2026/8/5 3:12:13

ET框架Unity Package本地开发环境配置与无缝调试技巧

ET框架Unity Package本地开发环境配置与无缝调试技巧 1. 项目概述为什么我们需要一个高效的本地开发环境做ET框架插件开发的朋友尤其是那些需要频繁修改核心库、调试服务端逻辑的肯定都经历过这样的痛苦循环在Unity里改了几行代码然后切到命令行去编译服务端再启动服务器最后在Unity客户端里连接测试。整个过程下来几分钟就过去了如果发现逻辑不对又要从头再来。这种开发体验效率低不说还特别容易打断思路。问题的核心在于我们通常把ET框架的核心库比如Model、Hotfix、ModelView、HotfixView这些做成了Unity Package通过Package Manager引入。这本身是模块化、依赖管理的好实践但它也把我们的修改和调试流程“隔离”开了。你无法像调试项目内的脚本那样在Unity编辑器中直接下断点、单步跟踪进入Package里的代码。更麻烦的是当你修改了Package中的代码你需要手动触发Package的重新编译和发布或者重启整个服务端进程才能看到效果。所以今天要聊的“ET框架插件调试技巧Unity Package本地开发环境配置”其核心目标就是打破这个隔离。我们要搭建一个环境让你能够实时修改即时生效在IDE如Rider/VS中修改Package源码Unity编辑器或服务端能近乎实时地热重载无需完整重启。无缝调试无论是Unity客户端的HotfixView逻辑还是服务端的Hotfix逻辑都能像调试普通项目代码一样下断点、看变量、逐行执行。流程自动化将编译、拷贝、重启等重复性操作自动化让开发者聚焦于业务逻辑本身。这不仅仅是配置几个路径那么简单它涉及到对Unity Package机制、ET框架的代码组织、编译流程以及调试器原理的深入理解和巧妙运用。下面我就把自己踩过无数坑后总结出来的、一套稳定高效的配置方案拆解给你看。2. 核心思路与方案选型从“引用”到“链接”的转变要达成上述目标我们首先要理解标准工作流为什么慢。当我们通过file:或git:协议从本地或版本库引用一个Package时Unity实际上是将Package的内容拷贝到项目的Library/PackageCache目录下进行使用的。你对原始Package目录的修改不会自动同步到PackageCache里除非你手动在Package Manager里更新该Package或者重启Unity编辑器有时会触发重新导入。这对于需要频繁修改的底层框架代码来说是不可接受的。因此我们的核心思路就是变“拷贝引用”为“符号链接”Symbolic Link或“直接路径引用”。让Unity项目直接使用我们本地开发目录下的Package源码任何修改都能立即被Unity识别。同时要确保ET服务端项目通常是控制台应用也能引用到同一份源码保证两端代码同步。2.1 方案对比哪种“链接”方式最适合ET主要有三种技术路径可以实现这个目标使用file:协议并配合 Assembly Definition References 的覆盖这是最“原生”但略显繁琐的方法。你仍然在manifest.json里用com.et.framework: file:../ET-Framework这样的方式引用。但关键在于你需要在你的游戏项目中创建与Package内同名的.asmdef文件并将其程序集引用指向本地路径。这种方法Unity官方支持度最好但配置复杂容易出错。使用path:注册表Unity 2019.4在Unity的Packages文件夹下创建manifest.json同级的packages-lock.json不更优雅的是使用本地的Scoped Registries。你可以搭建一个本地的npm或upm服务器将本地Package发布上去然后通过Scope注册表引用。这更像一个“准生产环境”适合团队共享但对于纯本地开发来说太重了。使用操作系统的符号链接Symbolic Link / Junction这是我最推荐也是实践中最稳定高效的方法。它的原理是在项目的Packages目录下创建一个指向你本地Package开发目录的符号链接在Windows上是mklink /J创建的目录联接在macOS/Linux上是ln -s创建的软链接。对于Unity和你的IDE来说这个链接就像是一个真实的文件夹所有读写操作都直接作用于源目录。为什么最终选择符号链接方案零延迟文件修改立即可见Unity的Asset Database能实时监测到变化。无需额外工具只需操作系统支持不依赖Unity特殊版本或第三方插件。双向同步无论是Unity编辑器内操作还是外部IDE修改修改的都是同一份物理文件。对ET框架天然友好ET的代码结构清晰Model,Hotfix等模块本身就是独立的.asmdef程序集非常适合整个文件夹进行链接。调试支持完美由于源码物理位置唯一无论是配置Unity调试还是配置服务端项目的调试都能直接指向这个唯一路径避免调试器找不到源码的尴尬。注意使用符号链接需要你对命令行操作有一定了解并且要确保版本控制系统如Git能正确处理符号链接通常需要额外配置。对于团队协作建议将符号链接的创建步骤写成脚本纳入项目仓库的初始化文档中。3. 详细配置实操一步步搭建无缝调试环境假设我们的目录结构如下D:\Dev\ ├── MyETGame/ # Unity客户端项目 │ ├── Assets/ │ ├── Packages/ │ │ └── (这里将创建符号链接) │ └── MyETGame.sln │ └── ETFramework/ # ET框架Package开发目录 ├── package.json # 包含name: com.et.framework ├── Editor/ ├── Runtime/ │ ├── Model/ │ ├── Hotfix/ │ ├── ModelView/ │ └── HotfixView/ └── ETFramework.sln3.1 第一步创建符号链接我们目标是让MyETGame/Packages/com.et.framework这个位置直接指向D:\Dev\ETFramework的内容。Windows (使用管理员权限打开CMD或PowerShell):# 首先删除Packages目录下可能已存在的如果是空的就不用管 # 然后创建目录联接Junction适用于目录 mklink /J D:\Dev\MyETGame\Packages\com.et.framework D:\Dev\ETFramework执行成功后你会在MyETGame/Packages/下看到一个名为com.et.framework的“快捷方式”图标文件夹双击可以正常访问。macOS / Linux:# 进入Unity项目的Packages目录 cd /Users/YourName/Dev/MyETGame/Packages # 创建软链接 ln -s /Users/YourName/Dev/ETFramework com.et.framework验证在Unity编辑器中打开MyETGame项目打开Window - Package Manager在“Packages: In Project”列表中你应该能看到一个来自本地通常显示为“Local”或文件路径的包com.et.framework。它的版本号由ETFramework/package.json中的version字段定义。3.2 第二步配置Unity项目以启用调试仅仅链接了源码还不够我们需要确保Unity能编译这些代码并且调试器能附加。设置Assembly Definition的编译平台打开ETFramework/Runtime/下的各个.asmdef文件如Model.asmdef,HotfixView.asmdef。在Inspector面板中确保“Platforms”包含了你需要的平台特别是Editor和你的目标平台如Standalone。对于Hotfix和Model它们通常不包含UnityEngine的API可能只编译为DLL供服务端使用但在Unity客户端项目中HotfixView和ModelView是必须启用的。配置Unity Editor的Script Debugging在Unity菜单栏选择Edit - Project Settings - Editor。将“Script Changes While Playing”设置为Recompile And Continue Playing。这允许你在游戏运行时修改脚本并尝试重新编译。虽然对ET的热重载有限但这是个好习惯。准备调试配置以Rider为例在Rider中打开你的MyETGame项目解决方案.sln。Rider通常会自动检测到通过符号链接引入的Package源码。如果没有你可以手动将ETFramework目录作为一个现有项目添加到解决方案中。确保ETFramework下的各个程序集项目其输出类型Output Type和目标框架Target Framework设置正确。例如纯服务端逻辑的项目应设为Class Library目标框架为.NET Core 3.1或.NET 6/8包含Unity API的项目其.csproj文件应包含对Unity程序集的正确引用这通常由Unity或Rider的插件管理。3.3 第三步配置服务端项目的调试环境ET服务端通常是一个独立的控制台应用程序例如App.dll它引用Model.dll和Hotfix.dll。我们需要让这个服务端项目也直接引用我们正在开发的源码而不是发布后的Package或拷贝的DLL。修改服务端项目文件(.csproj)找到你的服务端项目文件比如Server.Hotfix.csproj。修改它对Model和Hotfix的引用从引用编译后的DLL改为直接引用项目Project Reference。!-- 之前可能是这样 -- ItemGroup Reference IncludeModel HintPath..\..\Library\PackageCache\com.et.frameworkxxxxxx\Runtime\Model\bin\Debug\netcoreapp3.1\Model.dll/HintPath /Reference /ItemGroup !-- 改为这样 -- ItemGroup ProjectReference Include..\..\ETFramework\Runtime\Model\Model.csproj / ProjectReference Include..\..\ETFramework\Runtime\Hotfix\Hotfix.csproj / /ItemGroup这样当你编译服务端项目时它会自动先编译Model和Hotfix项目并且使用的是最新的源码。配置IDE以启动和调试在Rider或Visual Studio中将服务端项目设为启动项目。配置启动参数如--AppTypeServer等。现在你可以在Hotfix或Model的源码中设置断点然后启动调试F5。调试器会同时附加到服务端进程并在你修改了Hotfix源码后重新编译服务端项目即可再次调试。3.4 第四步实现近似热重载的工作流完全的C#热重载在复杂框架中难以实现但我们可以通过组合以下技巧极大提升迭代速度Unity端使用IHotfixAssembly接口与AssemblyBuilder。ET框架本身支持将HotfixView编译为DLL并动态加载。你可以编写一个Editor工具监听ETFramework/Runtime/HotfixView目录的文件变化使用FileSystemWatcher或Unity的AssetPostprocessor当.cs文件发生变化时自动触发以下流程调用CodeLoader的重新编译方法如果框架暴露了的话。或者更直接一点在Editor模式下你可以设计一个机制在按下某个快捷键如CtrlR时卸载当前的Hotfix程序集重新编译并加载新的。这需要你深入理解ET框架的代码加载机制并进行一些定制。服务端端进程外调试与快速重启。进程外调试不直接调试App.dll的进程而是调试一个“加载器”进程。这个加载器启动服务端App并监视Hotfix.dll的文件更改时间戳。当检测到Hotfix项目重新编译后加载器通知服务端App卸载旧程序集、加载新程序集。这需要较强的框架改造能力。快速重启脚本对于大多数调试场景一个更实用的方法是编写一个Shell脚本或PowerShell脚本、Bat文件它依次执行杀死旧服务端进程 - 编译服务端项目 - 启动新服务端进程。然后配合IDE的“外部工具”配置将这个脚本绑定到一个快捷键上。这样你修改完Hotfix代码后按一下快捷键10秒内就能重启服务端并看到效果比手动操作快得多。4. 常见问题、排查技巧与避坑指南即使按照步骤配置你也可能会遇到各种奇怪的问题。这里记录了一些高频问题和我的解决方案。4.1 Unity无法识别符号链接的Package现象Package Manager里看不到本地包或者显示为灰色、带错误图标。排查检查链接创建是否正确在命令行中进入MyETGame/Packages目录执行dir(Windows)或ls -la(macOS/Linux)。确认com.et.framework是一个链接并且其指向的路径正确无误。检查package.json确保ETFramework/package.json文件存在且格式正确。name字段必须与链接的文件夹名完全一致com.et.framework。version字段符合语义化版本规范。重启Unity并刷新有时Unity的Package数据库需要刷新。关闭Unity删除项目下的Library和obj文件夹注意备份然后重新打开项目。这是一个“万能”的清理缓存方法。权限问题确保Unity进程有权限读取符号链接指向的源目录。4.2 调试器无法命中断点源码不匹配现象在Rider/VS中设置了断点但启动调试后断点显示为空心圆提示“当前不会命中断点源代码与原始版本不同”。原因这是调试中最常见的问题根本原因是调试器加载的符号文件PDB中记录的源码路径与你IDE中打开的源码路径不一致。解决确保唯一源码路径这正是我们使用符号链接的核心目的。检查你的服务端项目引用的Model.csproj和Hotfix.csproj的路径是否直接指向了ETFramework开发目录下的项目文件。绝对不要引用任何bin\Debug下的DLL。清理并重建在IDE中执行“Clean Solution”然后“Rebuild Solution”。确保所有输出目录如binobj都被清理从头编译。检查调试符号设置在项目属性 - Build - Advanced 中确保“Debugging information”设置为“Portable”或“Full”.NET Core/.NET 5项目通常为“Portable”。这确保生成正确的PDB文件。在Rider中手动加载符号/源码如果上述步骤无效在Rider的Debug工具窗口当程序停在某个位置时右键点击调用堆栈中来自你的程序集的帧选择“Load Symbols”或“Show Sources”然后手动导航到ETFramework目录下的对应源文件。4.3 编译错误命名空间冲突或重复类型定义现象Unity或服务端项目编译时报错提示“The type ‘XXX’ exists in both ‘Assembly-CSharp, Version...’ and ‘Model, Version...’”。原因这通常是因为同一份代码被包含了两次。可能的情况有除了符号链接的Package你的Assets目录下某处还残留着ET框架的源码文件。你的.asmdef文件配置有误导致程序集引用范围重叠。通过不同方式Project Reference和DLL Reference重复引用了同一个程序集。解决彻底搜索整个Unity项目目录包括Assets查找是否在其他地方存在ModelHotfix等文件夹并删除或排除它们。仔细检查所有.asmdef文件的“Assembly Definition References”和“Version Defines”避免循环引用或包含关系混乱。ET框架自身的.asmdef引用关系通常是设计好的不要随意改动。检查服务端项目的.csproj文件确保没有同时存在ProjectReference和Reference指向同一个程序集。4.4 文件监视与热重载脚本的稳定性问题现象自己写的自动编译/重载脚本有时不触发或者触发后导致Unity编辑器卡死、崩溃。心得不要过度监视使用FileSystemWatcher时要设置合适的NotifyFilter如NotifyFilters.LastWrite和Filter如*.cs并处理CreatedChangedRenamed事件。注意一些编辑器如VS在保存文件时可能会触发多次Changed事件需要做防抖Debounce处理例如在文件变更后等待500毫秒再执行操作。在Unity主线程执行操作任何涉及Unity API如重新加载程序集、刷新AssetDatabase的操作都必须在主线程执行。可以在FileSystemWatcher的事件回调中将任务放入一个队列然后在Unity的Update循环或使用UnityMainThreadDispatcher这类工具来执行。做好错误处理与日志脚本中每一个可能失败的环节如编译命令、加载DLL都要用try-catch包裹并将错误信息输出到Unity控制台或日志文件便于排查。提供一个手动触发按钮无论自动脚本多智能在Editor GUI上提供一个“强制重载”按钮永远是明智的。当自动脚本失效时你可以手动点击。5. 高级技巧将配置脚本化与团队协作对于个人开发者上述手动配置可能就够了。但对于团队我们必须让环境搭建变得可重复、一键完成。5.1 创建项目初始化脚本编写一个init-dev-env.ps1Windows PowerShell或init-dev-env.shmacOS/Linux脚本放在项目仓库根目录。新成员拉取代码后只需运行这个脚本# init-dev-env.ps1 示例 (Windows) Write-Host 正在设置ET框架本地开发环境... -ForegroundColor Green # 1. 定义路径 $UNITY_PROJECT_PATH D:\Dev\MyETGame $ET_PACKAGE_SOURCE_PATH D:\Dev\ETFramework $PACKAGE_LINK_NAME com.et.framework $PACKAGE_LINK_PATH Join-Path $UNITY_PROJECT_PATH Packages $PACKAGE_LINK_NAME # 2. 检查源目录是否存在 if (-Not (Test-Path $ET_PACKAGE_SOURCE_PATH)) { Write-Host 错误: ET框架源码目录不存在: $ET_PACKAGE_SOURCE_PATH -ForegroundColor Red Write-Host 请先将ET框架仓库克隆到该目录。 -ForegroundColor Yellow exit 1 } # 3. 删除可能已存在的链接或文件夹 if (Test-Path $PACKAGE_LINK_PATH) { Write-Host 发现已存在的链接或目录正在删除... -ForegroundColor Yellow # 判断是否是链接目录联接 $item Get-Item $PACKAGE_LINK_PATH -Force if ($item.LinkType -eq Junction) { cmd /c rmdir $PACKAGE_LINK_PATH } else { Remove-Item $PACKAGE_LINK_PATH -Recurse -Force } } # 4. 创建目录联接需要管理员权限不一定但可能需要 Write-Host 正在创建符号链接... -ForegroundColor Cyan try { cmd /c mklink /J $PACKAGE_LINK_PATH $ET_PACKAGE_SOURCE_PATH Write-Host 符号链接创建成功 -ForegroundColor Green } catch { Write-Host 创建链接失败请尝试以管理员身份运行此脚本。 -ForegroundColor Red Write-Host 错误信息: $_ -ForegroundColor Red } # 5. 提示后续操作 Write-Host n环境初始化完成。请执行以下操作 -ForegroundColor Green Write-Host 1. 用Rider或VS打开 $UNITY_PROJECT_PATH\.sln 文件。 -ForegroundColor White Write-Host 2. 打开Unity编辑器等待Package Manager刷新。 -ForegroundColor White Write-Host 3. 参考文档配置服务端项目的项目引用。 -ForegroundColor White5.2 版本控制注意事项忽略链接文件在Unity项目的.gitignore文件中添加/Packages/com.et.framework因为这是一个指向个人本地路径的链接不应该提交到仓库。提交package.json引用在MyETGame/Packages/manifest.json中对于com.et.framework的依赖可以暂时保留为file:../ETFramework。这样即使没有运行初始化脚本其他开发者通过Package Manager的“Update”按钮仍然可以手动定位到ET框架的源码目录如果他们将其放在了同级目录。更好的做法是在团队内部约定一个固定的相对路径。文档化在项目的README.md中清晰说明本地开发环境的搭建步骤并附上初始化脚本的使用方法。经过这样一番配置你的ET框架插件开发体验将会得到质的飞跃。从修改代码到看到效果从下断点到命中调试整个流程变得顺畅无比。这背后虽然有一些前期的学习成本和配置工作但相比于长期在低效循环中消耗的时间和耐心这笔投资绝对物超所值。记住好的开发环境不是变魔术而是通过理解工具链的原理将那些重复、琐碎、耗时的环节自动化、无缝化让你能更专注地思考架构和逻辑本身。