一、Utils - 工具与实用方法
1. 资源与路径相关
1.1 获取 Sprite 资源
ResourceUtils.LoadSpriteFromAssembly("资源位置", 像素大小)
- 描述: 从程序集的嵌入资源中加载一张图片并返回为 Sprite 对象
- 参数:
- 资源位置: 资源文件名(例如 "Example.png"),无需完整路径
- 像素大小: Sprite 的像素大小,默认为 100f
- 返回值: Sprite,可直接赋给 SpriteRenderer
- 命名空间: COG.Utils
1.2 获取 Among Us 游戏目录
PathUtils.GetAmongUsPath(string additionPath = "")
- 描述: 通过查找正在运行的 "Among Us" 进程,获取其游戏根目录的绝对路径。可选地拼接一个子路径
- 参数:
- additionPath: 需要追加到根目录后的子路径(例如 "BepInEx\plugins")
- 返回值: 游戏目录的完整路径字符串,如果未找到进程则返回 null
- 命名空间: COG.Utils
1.3 从嵌入资源复制文件到磁盘
PathUtils.CopyResourcesToDisk(string targetDirectory, string embeddedDirectory, bool overwrite = true)
- 描述: 将程序集中指定嵌入资源目录下的所有文件,递归地复制到磁盘上的目标文件夹中
- 参数:
- targetDirectory: 磁盘上的目标文件夹路径
- embeddedDirectory: 程序集内嵌入资源的相对目录名(例如 "Images" 对应 COG.Resources.Images)
- overwrite: 是否覆盖已存在的文件
- 命名空间: COG.Utils
2. 网络与更新相关
2.1 下载文件 (协程)
AdvancedExampleCoroutine("文件 url", "文件绝对路径")
- 描述: 一个 IEnumerator 协程方法,用于从指定 URL 下载文件并保存到本地绝对路径
- 参数:
- 文件 url: 要下载文件的网络地址
- 文件绝对路径: 文件在本地磁盘上保存的完整路径(包含文件名)
- 使用案例:
public static IEnumerator DownloadYaml()
{
yield return AdvancedExampleCoroutine(
"https://xtreme.net.cn/upload/YamlDotNet.dll",
@$"{PathUtils.GetAmongUsPath()}BepInExcore"
);
}
2.2 检查模组更新
ModUpdater.FetchUpdate()
- 描述: (当前实现被注释掉)尝试从 GitHub API 获取模组的最新版本信息和更新日志,并存储在 ModUpdater.LatestVersion 和 ModUpdater.LatestDescription 中
- 命名空间: COG.Utils
2.3 执行模组更新
ModUpdater.DoUpdate()
- 描述: 从预设的服务器下载最新版本的 COG.dll,并通过一个 VBScript 脚本在游戏关闭后替换旧文件
- 命名空间: COG.Utils
2.4 获取网页内容
WebUtils.GetWeb(string url)
- 描述: 同步地向指定 URL 发送 GET 请求,并返回网页的文本内容
- 参数:
- 返回值: 网页的源代码字符串,失败时返回空字符串
- 命名空间: COG.Utils
3. 日志与调试相关
3.1 带调用栈的日志记录器
类: StackTraceLogger
- 描述: 一个增强的日志记录器,能自动在日志消息前附加 [类名::方法名] 的前缀,便于追踪日志来源。支持禁用特定类型或方法的日志输出
- 主要方法:
- LogInfo, LogError, LogWarning 等:记录不同级别的日志
- DisableSource(Type toDisable): 禁用某个类的所有日志
- EnableSource(Type toEnable): 启用某个类的日志
- 命名空间: COG.Utils
3.2 对象转储 (Dump)
LoggerUtils.Dump(this T obj)
- 描述: 一个扩展方法,用于快速将对象的内容打印到日志中,并返回该对象本身,方便链式调用
- 命名空间: COG.Utils
4. 游戏逻辑与玩家相关
4.1 获取 Among Us 游戏选项
GameUtils.GetGameOptions()
- 描述: 获取当前游戏的 NormalGameOptionsV10 实例,可用于读取或修改游戏设置(如击杀距离、内鬼数量等)
- 返回值: NormalGameOptionsV10
- 命名空间: COG.Utils
4.2 获取当前启用的内鬼数量
GameUtils.GetImpostorsNumber()
- 描述: 根据当前房间的玩家总数和游戏设置,计算出实际生效的内鬼数量
- 返回值: int
- 命名空间: COG.Utils
4.3 在游戏中发送消息
GameUtils.SendGameMessage(string text)
- 描述: 在屏幕顶部发送一条类似断开连接的红色提示消息
- 参数:
- 命名空间: COG.Utils
4.4 获取所有玩家
PlayerUtils.GetAllPlayers()
- 描述: 获取当前游戏中所有玩家的 PlayerControl 列表
- 返回值: List<PlayerControl>
- 命名空间: COG.Utils
4.5 获取所有存活玩家
PlayerUtils.GetAllAlivePlayers()
- 描述: 获取当前游戏中所有存活玩家的 PlayerControl 列表
- 返回值: List<PlayerControl>
- 命名空间: COG.Utils
4.6 杀死玩家(不生成尸体)
PlayerUtils.RpcKillWithoutDeadBody(this PlayerControl killer, PlayerControl target, ...)
- 描述: 通过 RPC 调用杀死一名玩家,但不会在游戏中生成尸体(DeadBody)
- 命名空间: COG.Utils
4.7 复活玩家
PlayerUtils.RpcRevive(this PlayerControl player)
- 描述: 通过 RPC 调用复活一名已死亡的玩家
- 命名空间: COG.Utils
4.8 设置玩家自定义职业
PlayerUtils.RpcSetCustomRole(this PlayerControl pc) where T : CustomRole
- 描述: 通过 RPC 调用,将一名玩家的职业设置为指定的自定义职业 T
- 命名空间: COG.Utils
5. UI 与视觉效果相关
5.1 创建浮动文本
类: FloatingText
- 描述: 在屏幕指定位置创建一个可自定义的浮动文本(类似于 PingTracker)
- 主要方法:
- 构造函数: new FloatingText(...) 初始化配置
- Create(string text): 创建并显示文本
- Destroy(): 销毁文本对象
- 命名空间: COG.Utils
5.2 显示浮动文本 (协程)
IEnumeratorUtils.CoShowText(string text, Vector3 vector, Color color, float duration, int fontsize, TextAlignmentOptions alignment)
- 描述: 一个协程,用于在指定世界坐标位置显示一个彩色浮动文本,并在 duration 秒后自动销毁
- 命名空间: COG.Utils
5.3 为 GameObject 创建子对象
GameObjectUtils.CreateObject(string objName, Transform parent, Vector3 localPosition, int? layer = null)
- 描述: 在指定父对象下创建一个新的 GameObject,并设置其名称、局部位置和层级
- 返回值: 新创建的 GameObject
- 命名空间: COG.Utils
5.4 安全销毁对象
GameObjectUtils.TryDestroy(this Object? obj)
- 描述: 一个扩展方法,在销毁 Unity 对象前先检查其是否为 null,避免报错
- 命名空间: COG.Utils
6. 工具与辅助方法
6.1 颜色工具
类: ColorUtils
- 描述: 提供颜色相关的实用方法
- 主要方法:
- ToColorString(this Color color, string str): 将字符串包裹在 Rich Text 颜色标签中
- AsColor(string color): 将十六进制颜色字符串(如 "#FF0000")转换为 Color 对象
- GradientColorText(...): 生成带有渐变色彩的 Rich Text 字符串
- 命名空间: COG.Utils
6.2 集合工具
类: CollectionUtils
- 描述: 为集合(尤其是 List)提供扩展方法
- 主要方法:
- Disarrange(this IEnumerable list): 打乱列表顺序
- Pop(this List list): 弹出并移除列表的第一个元素
- ForEach(this IEnumerable collection, Action action): 为集合中的每个元素执行操作
- AsString(...): 将集合作为字符串输出,便于调试
- 命名空间: COG.Utils
6.3 字符串工具
类: StringUtils
- 描述: 提供字符串处理的扩展方法
- 主要方法:
- GetSHA1Hash(this string input): 计算字符串的 SHA1 哈希值
- CustomFormat(this string text, params object[] args): 使用 % 作为占位符进行字符串格式化
- EncodeToBase64 / DecodeAsBase64: 进行 Base64 编码和解码
- 命名空间: COG.Utils
6.4 Yaml 解析器
类: Yaml
- 描述: 一个用于加载、解析和操作 Yaml 文件/字符串的工具类
- 主要方法:
- LoadFromFile(string path): 从文件加载 Yaml
- LoadFromString(string text): 从字符串加载 Yaml
- GetInt / GetBool / GetString / GetStringList(string location): 根据路径(如 "player.health")获取对应的值
- WriteTo(string path): 将修改后的 Yaml 内容写回文件
- 命名空间: COG.Utils
二、重要方法 - 核心系统功能
1. 配置系统 (Config System)
1.1 配置基类
ConfigBase
- 描述: 所有配置类的基类,用于加载和管理配置文件
- 主要方法:
- LoadConfigs(bool replace = false):
- 功能: 加载配置文件。如果文件不存在或需要覆盖,则创建新文件;否则从文件加载配置
- 参数:
- replace: 是否覆盖现有配置文件(默认为 false)
- 流程:
- 创建数据目录 DataDirectoryName(默认为 COG_DATA)
- 如果文件存在且 replace 或 AutoReplace 为 true,则备份原文件
- 如果文件不存在或需要覆盖,则写入默认配置文本
- 否则从文件加载配置文本
- 解析 YAML 内容到 YamlReader
- 命名空间: COG.Config
1.2 配置类
SettingsConfig
- 描述: 系统设置配置类,继承自 ConfigBase
- 主要属性:
- EnablePluginSystem: 是否启用插件系统(从配置文件中读取)
- TimeZone: 时区设置(从配置文件中读取)
- Culture: 语言文化设置(从配置文件中读取)
- Strict: 严格模式(从配置文件中读取)
- 初始化:
- static SettingsConfig(): 静态构造函数,创建单例实例
- SettingsConfig(): 构造函数,加载 settings.yml 配置文件
- 命名空间: COG.Config.Impl
LanguageConfig
- 描述: 语言配置类,继承自 ConfigBase,处理多语言支持
- 主要属性:
- 大量字符串属性(如 MakePublicMessage, Yes, No, Cancel, Confirm 等),用于存储不同语言的翻译文本
- 主要方法:
- GetString(string location):
- 功能: 从语言配置中获取指定路径的翻译字符串
- 参数:
- location: 翻译字符串的路径(如 "lobby.make-public-message")
- 返回值: 翻译后的字符串,如果找不到则返回原始路径
- SetTranslations():
- 功能: 从配置文件加载所有翻译字符串
- 流程:
- 使用 GetString 方法获取每个翻译字符串
- 将获取的字符串赋值给相应的属性
- 处理异常(如果加载失败,则显示错误消息并创建新实例)
- 注意: 使用LanguageConfig时,请使用LanguageConfig.Instance获取LanguageConfig实例
- 命名空间: COG.Config.Impl
2. 自定义选项系统 (Custom Options System)
2.1 选项值规则
IValueRule
- 描述: 值规则接口,用于定义选项的合法值、默认值和验证逻辑
- 主要属性:
- DefaultSelection: 默认选择的索引
- Selections: 选项的合法值数组
- 命名空间: COG.UI.CustomOption.ValueRules
StringOptionValueRule
- 描述: 字符串选项值规则实现
- 主要方法:
- IsValid(string item):
- 功能: 验证字符串是否在合法值列表中
- 返回值: 如果字符串有效则返回 true,否则返回 false
- 命名空间: COG.UI.CustomOption.ValueRules.Impl
IntOptionValueRule
- 描述: 整数选项值规则实现
- 主要方法:
- IsValid(int obj):
- 功能: 验证整数是否在合法范围内
- 返回值: 如果整数有效则返回 true,否则返回 false
- Validate(ref int obj):
- 功能: 将值调整到合法范围内
- 参数: obj - 需要验证的值
- 命名空间: COG.UI.CustomOption.ValueRules.Impl
FloatOptionValueRule
- 描述: 浮点数选项值规则实现
- 主要方法:
- IsValid(float obj):
- 功能: 验证浮点数是否在合法范围内
- 返回值: 如果浮点数有效则返回 true,否则返回 false
- Validate(ref float obj):
- 功能: 将值调整到合法范围内
- 参数: obj - 需要验证的值
- 命名空间: COG.UI.CustomOption.ValueRules.Impl
BoolOptionValueRule
- 描述: 布尔选项值规则实现
- 主要方法:
- IsValid(bool obj):
- 功能: 验证布尔值是否有效(总是有效)
- 返回值: 总是返回 true
- 命名空间: COG.UI.CustomOption.ValueRules.Impl
2.2 自定义选项
CustomOption
- 描述: 自定义选项类,用于在游戏中创建和管理自定义选项
- 主要属性:
- Id: 选项的唯一标识符
- Name: 选项的名称(通过委托获取)
- Page: 选项所属的页面类型(TabType)
- ValueRule: 选项的值规则(实现 IValueRule)
- Selection: 当前选择的索引
- 主要方法:
- Of<T>(TabType type, Func<string> nameGetter, IValueRule rule, CustomOption? parent = null):
- 功能: 创建一个新的自定义选项实例
- 参数:
- type: 选项所属的页面类型
- nameGetter: 获取选项名称的委托
- rule: 选项的值规则
- parent: 父选项(如果存在)
- 返回值: 新创建的 CustomOption 实例
- Register():
- 功能: 注册选项,使其在游戏设置中可用
- 返回值: 选项自身
- GetBool():
- 功能: 获取选项的布尔值
- 返回值: 选项的当前选择的布尔值
- GetInt():
- 功能: 获取选项的整数值
- 返回值: 选项的当前选择的整数值
- GetString():
- 功能: 获取选项的字符串值
- 返回值: 选项的当前选择的字符串值
- 命名空间: COG.UI.CustomOption
GlobalCustomOptionConstant
- 描述: 全局自定义选项常量类,用于定义和注册常用选项
- 主要属性:
- DebugMode: 调试模式选项
- MaxAddonNumber: 最大附加职业数量选项
- MaxNeutralNumber: 最大中立角色数量选项
- 初始化:
- static GlobalCustomOptionConstant(): 静态构造函数,初始化选项
- 命名空间: COG.Constant
3. 自定义按钮系统 (Custom Button System)
3.1 按钮管理器
CustomButtonManager
- 描述: 自定义按钮管理器,用于注册和管理所有自定义按钮
- 主要方法:
- RegisterCustomButton(CustomButton button):
- 功能: 注册一个自定义按钮
- 参数: button - 要注册的按钮实例
- RegisterCustomButtons(IEnumerable<CustomButton> buttons):
- 功能: 注册多个自定义按钮
- 参数: buttons - 要注册的按钮集合
- GetButtons():
- 功能: 获取所有注册的自定义按钮
- 返回值: 按钮列表
- 命名空间: COG.UI.Hud.CustomButton
3.2 自定义按钮
CustomButton
- 描述: 自定义按钮类,用于在游戏中创建和管理自定义按钮
- 主要属性:
- Id: 按钮的唯一标识符
- Identifier: 按钮的标识符
- OnClick: 按钮点击时的回调函数
- OnMeetingEnds: 会议结束时的回调函数
- OnEffect: 按钮效果结束时的回调函数
- CouldUse: 按钮是否可用的条件
- HasButton: 玩家是否拥有此按钮的条件
- Sprite: 按钮的图标
- Position: 按钮的位置
- Text: 按钮的文本
- Cooldown: 按钮的冷却时间
- EffectTime: 按钮效果持续时间
- UsesLimit: 按钮使用次数限制
- Hotkey: 按钮的热键
- 主要方法:
- Of(string identifier, Action onClick, Action onMeetingEnds, Action onEffect, Func<bool> couldUse, Func<bool> hasButton, Sprite sprite, Vector3 position, string text, Func<float> cooldown, float effectTime, int usesLimit, KeyCode hotkey, bool isMeetingButton, int order = -1):
- 功能: 创建一个带效果的自定义按钮实例
- 参数:
- identifier: 按钮的标识符
- onClick: 按钮点击时的回调函数
- onMeetingEnds: 会议结束时的回调函数
- onEffect: 按钮效果结束时的回调函数
- couldUse: 按钮是否可用的条件
- hasButton: 玩家是否拥有此按钮的条件
- sprite: 按钮的图标
- position: 按钮的位置
- text: 按钮的文本
- cooldown: 按钮的冷却时间
- effectTime: 按钮效果持续时间
- usesLimit: 按钮使用次数限制
- hotkey: 按钮的热键
- isMeetingButton: 是否是会议按钮
- order: 按钮在 HUD 中的顺序
- 返回值: 创建的 CustomButton 实例
- Of(string identifier, Action onClick, Action onMeetingEnds, Func<bool> couldUse, Func<bool> hasButton, Sprite sprite, Vector3 position, string text, Func<float> cooldown, int usesLimit, KeyCode hotkey, bool isMeetingButton, int order = -1):
- 功能: 创建一个不带效果的自定义按钮实例
- 参数: 与上述方法类似,但不包含 onEffect 参数
- SetActive(bool active):
- 功能: 设置按钮的可见性
- 参数: active - 是否显示按钮
- Update():
- 命名空间: COG.UI.Hud.CustomButton
3.3 玩家选择菜单系统
PlayetSelectMenu.cs 文件实现了COG模组中的玩家选择菜单功能,这是一个用于在游戏会议期间提供玩家选择界面的UI组件。
3.3.1 核心类结构
PlayerSelectionManager 类
public class PlayerSelectionManager {
private static List<PlayerSelectionUI> _activeInstances = new List<PlayerSelectionUI>();
public static PlayerSelectionUI CreateSelectionUI(string titleText = "选择玩家", Action<PlayerControl> onPlayerSelected = null) {
// 创建并返回新的PlayerSelectionUI实例
}
public static void CleanupAllInstances() {
// 清理所有活动的玩家选择UI
}
}
功能说明:
- 作为全局管理器,确保同一时间只有一个玩家选择菜单实例存在
- 提供创建菜单的便捷方法,支持自定义标题和选择回调
- 确保菜单资源的正确清理,避免内存泄漏
PlayerSelectionUI 类
public class PlayerSelectionUI {
public string TitleText { get; private set; }
public PlayerControl SelectedPlayer { get; private set; }
public GameObject UIInstance { get; private set; }
// 构造函数
public PlayerSelectionUI(MeetingHud meetingHud, string titleText, Action<PlayerControl> onPlayerSelected = null) {
// 初始化UI
}
// 显示UI
public void ShowPlayerSelectionUI() {
// 创建并显示选择菜单
}
// 创建UI元素
private void CreateUIElements(Transform container) {
// 创建标题、退出按钮和玩家按钮
}
// 处理玩家按钮点击
private void OnPlayerButtonClicked(PlayerControl player, Transform button) {
// 选择玩家并触发回调
}
// 关闭UI
public void CloseSelectionUI() {
// 清理UI并恢复游戏状态
}
public void Cleanup() {
// 完全清理UI资源
}
}
4. 自定义角色系统 (Custom Role System)
4.1 角色管理
CustomRoleManager
- 描述: 自定义角色管理器,用于注册和管理所有自定义角色
- 主要方法:
- RegisterRole(CustomRole role):
- 功能: 注册一个自定义角色
- 参数: role - 要注册的角色实例
- RegisterRoles(CustomRole[] roles):
- 功能: 注册多个自定义角色
- 参数: roles - 要注册的角色数组
- GetTypeCampRoles(CampType campType):
- 功能: 获取指定阵营的所有角色
- 参数: campType - 角色阵营类型
- 返回值: 指定阵营的角色数组
- GetRoles():
- 功能: 获取所有自定义角色
- 返回值: 所有自定义角色的列表
- GetModRoles():
- 功能: 获取所有模组角色(非基础角色)
- 返回值: 模组角色的列表
- 命名空间: COG.Role
4.2 角色基类
CustomRole
- 描述: 自定义角色基类,所有自定义角色必须继承此基类
- 主要属性:
- Id: 角色的唯一标识符
- Color: 角色的颜色
- Name: 角色的名称
- ShortName: 角色的简短名称
- CampType: 角色的阵营类型(CampType 枚举)
- CanKill: 是否可以击杀
- CanVent: 是否可以跳管
- CanSabotage: 是否可以破坏
- RoleNumberOption: 角色数量选项
- RoleChanceOption: 角色几率选项
- RoleCode: 角色代码选项
- AllButtons: 角色的所有按钮
- 主要方法:
- CreateOption(Func<string> nameGetter, IValueRule rule):
- 功能: 创建一个新的自定义选项
- 参数:
- nameGetter: 获取选项名称的委托
- rule: 选项的值规则
- 返回值: 创建的自定义选项
- AddButton(CustomButton button, Func<bool>? hasButton = null):
- 功能: 为角色添加一个自定义按钮
- 参数:
- button: 要添加的按钮
- hasButton: 玩家是否拥有此按钮的条件(默认为 PlayerControl.LocalPlayer.IsRole(this))
- GetLongDescription():
- 功能: 获取角色的详细介绍
- 返回值: 角色的详细介绍字符串
- IsAvailable():
- 功能: 检查角色是否可用(根据配置和随机数)
- 返回值: 如果角色可用则返回 true,否则返回 false
- 命名空间: COG.Role
CampType
- 描述: 角色阵营类型枚举
- 枚举值:
- Crewmate: 神职人员阵营
- Neutral: 中立阵营
- Impostor: 内鬼阵营
- Unknown: 未知阵营
- 命名空间: COG.Role
ModiType
- 描述: 附加职业类型枚举
- 枚举值:
- Addon: 附加职业
- SubRole: 子职业
- Unknown: 未知类型
- 命名空间: COG.Role
OnlyOnRoleType
- 描述: 附加职业适用类型枚举
- 枚举值:
- None: 无限制
- Crewmate: 仅限神职人员
- Neutral: 仅限中立角色
- Impostor: 仅限内鬼
- Global: 全局适用
- 命名空间: COG.Role
5. 角色按钮系统 (Role Button System)
5.1 按钮设置
KillButtonSetting
- 描述: 击杀按钮设置类,用于自定义击杀按钮的行为
- 主要属性:
- ForceShow: 是否强制显示按钮的条件
- TargetOutlineColor: 目标轮廓颜色
- 主要方法:
- AddAfterClick(Action action):
- 功能: 添加点击后执行的操作
- 参数: action - 点击后执行的操作
- 命名空间: COG.Role
5.2 角色按钮
RoleButton
- 描述: 角色按钮类,用于表示角色的击杀按钮
- 主要属性:
- 主要方法:
- 命名空间: COG.Role
5.3 角色按钮系统
5.3.1 击杀按钮设置
KillButtonSetting 类
- 描述: 击杀按钮设置类,用于自定义击杀按钮的行为
- 主要属性:
- ForceShow: 获取或设置一个委托,用于判断是否强制显示按钮的条件
- TargetOutlineColor: 获取或设置目标玩家轮廓的颜色
- 主要方法:
- AddAfterClick(Action action)
- 命名空间: COG.Role
5.3.2 角色按钮
RoleButton 类
- 描述: 角色按钮类,用于表示角色的击杀按钮
- 主要属性:
- Role: 获取关联的角色实例
- Button: 获取按钮对象
- 主要方法:
- 命名空间: COG.Role
6. 工具与辅助方法
6.1 颜色工具
ColorUtils 类
- 描述: 提供颜色相关的实用方法
- 主要方法:
- ToColorString(this Color color, string str)
- 功能: 将字符串包裹在 Rich Text 颜色标签中,使其显示为指定颜色
- 参数:
- 返回值: 带有颜色标签的字符串
- AsColor(string color)
- 功能: 将十六进制颜色字符串(如 "#FF0000")转换为 Color 对象
- 参数:
- 返回值: 对应的 Color 对象
- GradientColorText(...)
- 功能: 生成带有渐变色彩的 Rich Text 字符串
- 参数: 渐变颜色和文本内容
- 返回值: 带有渐变效果的字符串
- 命名空间: COG.Utils
6.2 集合工具
CollectionUtils 类
- 描述: 为集合(尤其是 List)提供扩展方法
- 主要方法:
- Disarrange<T>(this IEnumerable<T> list)
- 功能: 打乱列表顺序(随机排序)
- 返回值: 打乱顺序后的新列表
- Pop<T>(this List<T> list)
- 功能: 弹出并移除列表的第一个元素
- 返回值: 被移除的元素
- ForEach<T>(this IEnumerable<T> collection, Action<T> action)
- AsString<T>(...)
- 功能: 将集合作为格式化字符串输出,便于调试
- 返回值: 表示集合内容的字符串
- 命名空间: COG.Utils
6.3 字符串工具
StringUtils 类
- 描述: 提供字符串处理的扩展方法
- 主要方法:
- GetSHA1Hash(this string input)
- 功能: 计算字符串的 SHA1 哈希值
- 参数:
- 返回值: 哈希值的十六进制字符串表示
- CustomFormat(this string text, params object[] args)
- 功能: 使用 % 作为占位符进行字符串格式化(类似于 string.Format,但使用 % 代替 {0} 等)
- 参数:
- text: 包含 % 占位符的格式字符串
- args: 要插入到占位符的参数
- 返回值: 格式化后的字符串
- EncodeToBase64(this string text)
- 功能: 将字符串进行 Base64 编码
- 返回值: Base64 编码后的字符串
- DecodeAsBase64(this string base64Text)
- 功能: 将 Base64 字符串解码为原始字符串
- 返回值: 解码后的原始字符串
- 命名空间: COG.Utils
6.4 Yaml 解析器
Yaml 类
- 描述: 一个用于加载、解析和操作 Yaml 文件/字符串的工具类
- 主要方法:
- LoadFromFile(string path)
- 功能: 从文件加载 Yaml 内容
- 参数:
- 返回值: Yaml 实例
- LoadFromString(string text)
- 功能: 从字符串加载 Yaml 内容
- 参数:
- 返回值: Yaml 实例
- GetInt(string location)
- 功能: 根据路径(如 "player.health")获取对应的整数值
- 参数:
- 返回值: 找到的整数值
- GetBool(string location)
- 功能: 根据路径获取对应的布尔值
- 返回值: 找到的布尔值
- GetString(string location)
- 功能: 根据路径获取对应的字符串值
- 返回值: 找到的字符串值
- GetStringList(string location)
- 功能: 根据路径获取对应的字符串列表
- 返回值: 找到的字符串列表
- WriteTo(string path)
- 功能: 将修改后的 Yaml 内容写回文件
- 参数:
- 命名空间: COG.Utils
7. 自定义角色系统(Custom Role System)
7.1 注册自定义职业
CustomRole.Register<T>() 方法
- 描述: 在模组初始化阶段调用,用于将一个实现了 CustomRole 抽象类的新职业注册到系统中。注册后,该职业可在游戏逻辑中被分配和使用
- 泛型参数:
- 命名空间: COG.Roles
7.2 获取玩家的自定义职业
PlayerControl.GetCustomRole() 方法
- 描述: 扩展方法,返回当前玩家所拥有的 CustomRole 实例(如果已分配)
- 返回值: CustomRole 或 null
- 命名空间: COG.Roles
7.3 检查玩家是否拥有特定职业
PlayerControl.IsRole<T>() 方法
- 描述: 判断当前玩家是否被分配了指定类型的自定义职业
- 返回值: bool
- 命名空间: COG.Roles
7.4 职业行为钩子(示例)
在 CustomRole 基类及其派生类中通常会重写以下虚方法以实现职业逻辑:
- OnMeetingStart(): 会议开始时触发
- OnMeetingEnd(): 会议结束时触发
- OnKillAttempt(PlayerControl killer, PlayerControl target): 当此玩家尝试击杀或被击杀时触发
- OnFixedUpdate(): 每帧固定更新(类似 Update,但用于物理/游戏逻辑)
- OnTaskComplete(PlayerTask task): 玩家完成任务时触发
注意: 这些方法需由具体职业类实现,并通过 GameManager 或 RoleManager 在游戏事件中调用
8. 配置与本地化管理
8.1 加载配置文件
ConfigManager.LoadConfig(string fileName) 方法
- 描述: 从 BepInEx/config/ 目录加载指定名称的 JSON 配置文件(如 "COG.json"),并反序列化为 PluginConfig 对象
- 参数:
- 返回值: PluginConfig 实例
- 命名空间: COG.Config
8.2 保存配置
ConfigManager.SaveConfig(PluginConfig config, string fileName) 方法
- 描述: 将 PluginConfig 对象序列化并写回磁盘上的配置文件
- 参数:
- config: 要保存的配置对象
- fileName: 目标文件名
- 命名空间: COG.Config
8.3 获取本地化文本
Localization.GetString(string key) 方法
- 描述: 根据当前语言设置,从嵌入资源中的多语言 Yaml 文件(如 zh-CN.yaml, en-US.yaml)获取对应的本地化字符串
- 参数:
- key: 本地化键名(例如 "role.detective.name")
- 返回值: 本地化后的字符串,若未找到则返回键名本身
- 命名空间: COG.Localization
9. RPC(远程过程调用)通信
所有 RPC 方法均通过 Among Us 的 SendRPC 机制实现,确保多人游戏中同步。
9.1 发送自定义 RPC
RpcUtils.SendCustomRpc(byte callId, Action<BinaryWriter> writer) 方法
- 描述: 向服务器或其他客户端发送一条自定义的 RPC 消息
- 参数:
- callId: 自定义消息 ID(需全局唯一)
- writer: 写入附加数据的委托
- 命名空间: COG.Networking
9.2 处理接收到的 RPC
RpcUtils.OnReceiveCustomRpc 事件
- 描述: 订阅此事件以处理接收到的自定义 RPC 消息。根据 callId 分发逻辑
- 事件类型: Action<byte, BinaryReader>
- 用法示例:
RpcUtils.OnReceiveCustomRpc += (callId, reader) => {
if (callId == MyCustomRpcId) {
// 处理自定义 RPC
}
};
命名空间: COG.Networking
10. 游戏事件监听器
10.1 注册游戏事件回调
GameEvents.Subscribe<T>(Action<T> callback) 方法
- 描述: 订阅特定类型的游戏事件(如 PlayerKilledEvent, MeetingStartedEvent)。当事件发生时,自动调用回调函数
- 泛型参数:
- T: 要订阅的事件类型,必须实现 IGameEvent 接口
- 参数:
- 命名空间: COG.Events
10.2 触发自定义事件
GameEvents.Trigger<T>(T event) 方法
- 描述: 手动触发一个实现了 IGameEvent 接口的事件,通知所有订阅者
- 参数:
- 命名空间: COG.Events
11. 性能与内存优化
11.1 对象池管理器
ObjectPool<T> 类
- 描述: 泛型对象池,用于复用频繁创建/销毁的对象(如粒子效果、UI 元素),减少 GC 压力
- 主要方法:
- Get(): 从池中获取一个对象实例
- Return(T obj): 将对象归还至池中以便复用
- 命名空间: COG.Pooling
11.2 协程管理器
CoroutineManager 类
- 描述: 统一管理所有协程的启动与停止,避免因 MonoBehaviour 销毁导致的协程泄漏
- 主要方法:
- Start(IEnumerator routine): 安全启动协程
- StopAll(): 停止所有正在运行的协程
- 命名空间: COG.Coroutines
12. 调试与开发者工具
12.1 开发者控制台命令
DevConsole.RegisterCommand(string command, Action<string[]> handler) 方法
- 描述: 注册一个可通过 F1 控制台输入的调试命令(仅在 Debug 模式下启用)
- 参数:
- command: 命令名称
- handler: 命令处理函数,接收参数数组
- 用法示例:
DevConsole.RegisterCommand("killall", args => {
foreach (var p in PlayerUtils.GetAllAlivePlayers())
p.RpcMurderPlayer(p);
});
命名空间: COG.DevTools
12.2 性能分析标记
ProfilerUtils.BeginSample(string name) / EndSample() 方法
- 描述: 在 Unity Profiler 中添加自定义性能采样区域,便于定位性能瓶颈
- 用法示例:
ProfilerUtils.BeginSample("MyExpensiveOperation");
// 执行耗时操作
ProfilerUtils.EndSample();
命名空间: COG.Profiling
四、事件系统
4.1 事件系统概述
事件系统是COG模组的核心架构之一,用于处理游戏中的各种状态变化和交互行为。整个事件系统基于监听器模式实现,通过Event基类和IListener接口构成完整的事件处理框架。
4.2 事件系统核心架构
4.2.1 事件基类 (Event)
所有事件类都继承自Event基类,该基类提供了统一的事件标识机制:
- Name: 事件类型名称
- Id: 事件唯一标识符(基于名称哈希)
- GetSubClasses(): 获取所有事件子类的静态方法
4.2.2 事件处理器类型 (EventHandlerType)
定义了两种事件处理时机:
- Prefix: 在原始方法执行前调用
- Postfix: 在原始方法执行后调用
4.2.3 事件处理器属性 (EventHandlerAttribute)
用于标记监听器方法的特性,指定处理时机。
4.2.4 事件处理器 (Handler)
封装监听器实例的详细信息:
- Listener: 监听器实例
- Method: 处理方法
- EventType: 事件类型
- EventHandlerType: 处理时机类型
4.3 事件分类详解
4.3.1 游戏管理事件
GameStartManager相关事件
- GameStartManagerEvent: 游戏开始管理器事件基础类
- GameStartManagerUpdateEvent: 游戏开始管理器更新事件
- GameStartManagerStartEvent: 玩家进入大厅事件
- GameStartManagerMakePublicEvent: 房间公开化事件
- GameStartManagerBeginGameEvent: 游戏开始事件
AmongUsClient相关事件
- AmongUsClientEvent: 客户端事件基础类
- AmongUsClientPlayerJoinEvent: 玩家加入事件
- AmongUsClientLeaveEvent: 玩家离开事件
- AmongUsClientJoinLobbyEvent: 加入房间事件
- AmongUsClientGameEndEvent: 游戏结束事件
- AmongUsClientCreatePlayerEvent: 创建玩家事件
4.3.2 玩家相关事件
玩家基础事件 (PlayerEvent)
具体玩家事件
- PlayerTaskFinishEvent: 玩家完成任务事件
- PlayerShapeShiftEvent: 玩家变形事件
- PlayerReportDeadBodyEvent: 玩家报告尸体事件
- PlayerMurderEvent: 玩家击杀事件
- PlayerHandleRpcEvent: 玩家RPC处理事件
- PlayerFixedUpdateEvent: 玩家固定更新事件
- PlayerExileBeginEvent: 玩家驱逐开始事件
- PlayerExileEndEvent: 玩家驱逐结束事件
- PlayerExileEndOnAirshipEvent: 飞船地图驱逐结束事件
- PlayerCoSetTasksEvent: 玩家设置任务事件
- PlayerControlAwakeEvent: 玩家控制觉醒事件
- PlayerChatEvent: 玩家聊天事件
- LocalPlayerChatEvent: 本地玩家聊天事件
- PlayerAdjustLightingEvent: 玩家调整照明事件
自定义职业事件
- PlayerCustomRoleChangeEvent: 玩家自定义职业变更事件
4.3.3 会议相关事件
会议基础事件 (MeetingEvent)
具体会议事件
- MeetingStartEvent: 会议开始事件
- MeetingFixedUpdateEvent: 会议固定更新事件
- MeetingCastVoteEvent: 会议投票事件
- MeetingVotingCompleteEvent: 会议投票完成事件
- MeetingCheckForEndVotingEvent: 会议检查结束投票事件
- MeetingServerStartEvent: 服务器会议开始事件
4.3.4 游戏逻辑事件
游戏事件基础类
具体游戏事件
- GameStartEvent: 游戏开始事件
- GameCheckEndEvent: 游戏检查结束事件
- GameCheckTaskCompletionEvent: 游戏检查任务完成事件
- GameSetEverythingUpEvent: 游戏设置事件
- GameShowSabotageMapEvent: 显示破坏地图事件
- PingTrackerUpdateEvent: 延迟追踪更新事件
- OptionsMenuBehaviourUpdateEvent: 选项菜单更新事件
- OptionsMenuBehaviourStartEvent: 选项菜单开始事件
游戏记录事件
- StartGameEvent: 游戏开始记录事件
- StartMeetingEvent: 开始会议记录事件
- PlayerKillGameEvent: 玩家击杀记录事件
- PlayerDieGameEvent: 玩家死亡记录事件
- PlayerExileGameEvent: 玩家驱逐记录事件
- PlayerReviveGameEvent: 玩家复活记录事件
- PlayerDisconnectGameEvent: 玩家断开连接记录事件
- SheriffMisfireGameEvent: 警长误杀记录事件
- FinishTaskGameEvent: 完成任务记录事件
- EnterVentGameEvent: 进入通风管记录事件
- UseAbilityGameEvent: 使用能力记录事件
4.3.5 UI相关事件
HUD管理器事件
- HudManagerEvent: HUD管理器事件基础类
- HudManagerUpdateEvent: HUD更新事件
- HudManagerStartEvent: HUD开始事件
- HudManagerDestroyEvent: HUD销毁事件
按钮相关事件
- PassiveButtonEvent: 被动按钮事件基础类
- PassiveButtonClickEvent: 被动按钮点击事件
任务面板事件
- TaskPanelBehaviourEvent: 任务面板行为事件
- TaskPanelBehaviourSetTaskTextEvent: 设置任务文本事件
任务添加相关事件
- TaskAdderGameEvent: 任务添加游戏事件
- TaskAdderGameShowFolderEvent: 显示任务文件夹事件
- TaskAddButtonEvent: 任务添加按钮事件
- TaskAddButtonUpdateEvent: 任务按钮更新事件
- TaskAddButtonAddTaskEvent: 添加任务事件
4.3.6 角色和物理相关事件
角色管理事件
- RoleManagerEvent: 角色管理器事件
- RoleManagerSelectRolesEvent: 选择角色事件
玩家物理事件
- PlayerPhysicsEvent: 玩家物理事件
- PlayerPhysicsCoSpawnEvent: 玩家协同生成事件
4.3.7 地图元素事件
通风管事件
- VentEvent: 通风管事件基础类
- VentCheckEvent: 通风管检查事件
尸体事件
- DeadBodyEvent: 尸体事件基础类
- DeadBodyClickEvent: 尸体点击事件
控制器事件
- ControllerEvent: 控制器事件
- ControllerManagerUpdateEvent: 控制器管理器更新事件
4.3.8 过场动画事件
介绍过场事件
- IntroCutsceneEvent: 介绍过场事件基础类
- IntroCutsceneShowRoleEvent: 显示角色事件
- IntroCutsceneDestroyEvent: 过场销毁事件
- IntroCutsceneCoBeginEvent: 过场开始事件
- IntroCutsceneBeginImpostorEvent: 内鬼团队显示事件
- IntroCutsceneBeginCrewmateEvent: 船员团队显示事件
4.4 事件系统工作原理
4.4.1 事件注册机制
- 通过[EventHandler]特性标记监听方法
- 系统扫描所有标记的方法并创建Handler实例
- 按事件类型和处理时机分类存储
4.4.2 事件触发流程
- 游戏逻辑发生状态变化时触发对应事件
- 系统查找匹配的事件处理器
- 按照Prefix→原方法→Postfix的顺序执行处理器
- 处理器可以修改事件数据影响后续流程
4.4.3 事件数据传递
- 事件对象携带相关的游戏实体引用
- 支持数据修改(如VentCheckEvent中的SetCanUse方法)
- 保持事件数据的一致性和时效性
4.5 事件系统特点
4.5.1 层次化设计
事件系统采用多层继承结构,基础事件类提供通用功能,具体事件类扩展特定功能。
4.5.2 类型安全
通过泛型和类型检查确保事件处理器与事件类型的匹配。
4.5.3 灵活性
支持前置和后置处理,允许在不同时机介入游戏逻辑。
4.5.4 性能优化
通过类型索引快速定位事件处理器,减少运行时反射调用。
4.5.5 可扩展性
易于添加新的事件类型和处理器,支持模组功能的动态扩展。
事件系统为COG模组提供了强大的游戏逻辑拦截和修改能力,是实现各种自定义功能的基础架构。
五、参考角色书写模式
5.1 角色基类与分类
COG模组中的角色系统基于CustomRole基类构建,所有自定义角色都必须继承此类。角色主要分为以下几类:
- 基础角色(Base Role):如船员(Crewmate)、内鬼(Impostor)
- 职业角色(Custom Role):如预言家(Seer)、清道夫(Cleaner)、小丑(Jester)
- 附加身份(Addon):如疯子(Madman)
- 子身份(SubRole):如死亡威慑(DeathDeterrence)
- 未知角色(Unknown):用于占位或特殊用途
5.2 基础角色实现模式
5.2.1 船员角色 (Crewmate.cs)
public class Crewmate : CustomRole
{
public Crewmate() : base(Palette.CrewmateBlue, CampType.Crewmate, false)
{
IsBaseRole = true;
}
public override IListener GetListener()
{
return IListener.EmptyListener;
}
}
特点说明:
- 继承CustomRole基类
- 构造函数中设置颜色、阵营和是否为幽灵
- 标记IsBaseRole = true表示为基础角色
- 返回空监听器,不处理任何事件
5.2.2 内鬼角色 (Impostor.cs)
public class Impostor : CustomRole
{
public Impostor() : base(false)
{
CanKill = true;
CanVent = true;
IsBaseRole = true;
CanSabotage = true;
BaseRoleType = RoleTypes.Impostor;
}
}
特点说明:
- 通过布尔参数控制是否为幽灵状态
- 显式设置内鬼能力(击杀、通风管、破坏)
- 设置基础角色类型为RoleTypes.Impostor
5.3 职业角色实现模式
5.3.1 预言家角色 (Seer.cs)
public class Seer : CustomRole
{
// 私有字段声明
private CustomButton CheckButton { get; }
private int AvailableUsageTimes { get; set; }
private CustomOption Cooldown { get; }
private CustomOption InitialAvailableUsableTimes { get; }
private readonly Dictionary<byte, string> _prefixes = new();
private PlayerControl? _current;
private readonly HashSet<byte> _checkedPlayers = [];
// 构造函数
public Seer() : base(ColorUtils.FromColor32(30,144,255), CampType.Crewmate)
{
// 创建配置选项
Cooldown = CreateOption(() => GetContextFromLanguage("role.crewmate.seer-check-cooldown"),
new FloatOptionValueRule(5, 1, 60, 25, NumberSuffixes.Seconds));
InitialAvailableUsableTimes = CreateOption(() => GetContextFromLanguage("role.crewmate.seer-initial-available-usable-times"),
new FloatOptionValueRule(1, 1, 15, 1));
// 创建自定义按钮
var action = new LanguageConfig.TextHandler("action");
CheckButton = CustomButton.Of(
"seer-check",
() => { /* 执行逻辑 */ },
() => { }, // 重置逻辑
() => { /* 条件判断 */ },
() => true,
ResourceUtils.LoadSprite(ResourceConstant.CleanDeadBodyButton),
2,
action.GetString("check"),
() => Cooldown.GetFloat(),
-1
);
AddButton(CheckButton);
}
// 事件处理器方法
[OnlyLocalPlayerWithThisRoleInvokable]
[EventHandler(EventHandlerType.Postfix)]
public void OnPlayerMurder(PlayerMurderEvent @event) { }
[OnlyLocalPlayerWithThisRoleInvokable]
[EventHandler(EventHandlerType.Postfix)]
public void OnPlayerRoleChange(PlayerCustomRoleChangeEvent @event) { }
[OnlyLocalPlayerWithThisRoleInvokable]
[EventHandler(EventHandlerType.Postfix)]
public void OnGameStart(GameStartEvent _) { }
// 清理方法
public override void ClearRoleGameData()
{
_checkedPlayers.Clear();
_prefixes.Clear();
}
}
特点说明:
- 完整的角色生命周期管理
- 支持配置选项创建和管理
- 实现自定义按钮功能
- 使用事件监听器处理游戏事件
- 提供数据清理方法
- 使用特性标记限制调用条件
5.3.2 清道夫角色 (Cleaner.cs)
public class Cleaner : CustomRole, IListener
{
private DeadBody? _body;
public Cleaner()
{
BaseRoleType = RoleTypes.Impostor;
CanKill = true;
CanVent = true;
CanSabotage = true;
// 创建配置选项和按钮
CleanBodyCd = CreateOption(/* ... */);
CleanBodyButton = CustomButton.Of(/* ... */);
AddButton(CleanBodyButton);
}
private CustomOption CleanBodyCd { get; }
private CustomButton CleanBodyButton { get; }
public override IListener GetListener()
{
return this;
}
}
特点说明:
- 同时继承CustomRole并实现IListener接口
- 在构造函数中直接设置基础角色属性
- 通过GetListener()方法返回自身作为监听器
5.3.3 小丑角色 (Jester.cs)
public class Jester : CustomRole, IListener, IWinnable
{
private readonly CustomOption _allowReportDeadBody;
private readonly CustomOption _allowStartMeeting;
public Jester() : base(Color.magenta, CampType.Neutral)
{
_allowStartMeeting = CreateOption(/* ... */);
_allowReportDeadBody = CreateOption(/* ... */);
}
// 胜利条件检查
public void CheckWin(WinnableData data) { }
public uint GetWeight() { return IWinnable.GetOrder(5); }
// 事件处理器
[EventHandler(EventHandlerType.Prefix)]
public bool OnHostCheckStartMeeting(PlayerReportDeadBodyEvent @event) { }
public override IListener GetListener()
{
return this;
}
}
特点说明:
- 实现多个接口:IListener和IWinnable
- 支持自定义胜利条件
- 使用前缀事件处理器修改游戏行为
- 中立阵营角色的典型实现
5.4 特殊身份实现模式
5.4.1 附加身份 - 疯子 (Madman.cs)
public class Madman : CustomRole, IListener
{
public Madman() : base(Color.grey, ModiType.Addon, OnlyOnRoleType.Global)
{
}
// 使用Harmony补丁修改游戏文本
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), new Type[] { typeof(StringNames), typeof(Il2CppReferenceArray) })]
class ExileControllerMessagePatch
{
static void Postfix(ref string __result)
{
if (ExileController.Instance != null && ExileController.Instance.initData.networkedPlayer != null)
{
__result = "Madman";
}
}
}
}
特点说明:
- 使用ModiType.Addon标识为附加身份
- 使用Harmony补丁直接修改游戏原生方法
- 不需要复杂的事件监听,专注于特定功能
5.4.2 子身份 - 死亡威慑 (DeathDeterrence.cs)
public class DeathDeterrence : CustomRole, IListener
{
public DeathDeterrence() : base(Color.green, ModiType.SubRole, OnlyOnRoleType.Global)
{
DeterrenceCooldown = CreateOption(/* ... */);
DeterrenceButton = CustomButton.Of(/* ... */);
AddButton(DeterrenceButton);
}
private CustomOption DeterrenceCooldown { get; }
private CustomButton DeterrenceButton { get; }
}
特点说明:
- 使用ModiType.SubRole标识为子身份
- 可以独立拥有技能按钮和冷却时间
- 通常与其他主职业配合使用
5.4.3 未知角色 (Unknown.cs)
public class Unknown : CustomRole
{
public Unknown() : base(Color.white, CampType.Unknown)
{
BaseRoleType = RoleTypes.CrewmateGhost;
}
public override IListener GetListener()
{
return IListener.EmptyListener;
}
}
特点说明:
5.5 角色开发最佳实践
5.5.1 构造函数规范
- 必须调用基类构造函数
- 参数顺序:颜色、阵营类型、其他可选参数
- 在构造函数中完成所有初始化工作
5.5.2 字段声明规范
- 私有字段使用下划线前缀(如_checkedPlayers)
- 属性使用PascalCase命名(如CheckButton)
- 配置选项和按钮应声明为只读属性
5.5.3 事件处理规范
- 使用[EventHandler]特性标记事件处理器
- 根据需要选择Prefix或Postfix时机
- 对于仅本地玩家相关的事件,添加[OnlyLocalPlayerWithThisRoleInvokable]特性
5.5.4 资源管理规范
- 实现ClearRoleGameData()方法清理临时数据
- 避免内存泄漏,及时清理集合和引用
- 按钮和选项应在构造函数中创建并注册
5.5.5 接口实现规范
- 需要事件监听的角色实现IListener接口
- 需要自定义胜利条件的角色实现IWinnable接口
- 通过GetListener()方法返回适当的监听器实例
5.6 角色类型选择指南
| 角色类型 |
适用场景 |
继承方式 |
典型示例 |
| 基础角色 |
游戏默认角色 |
CustomRole |
Crewmate, Impostor |
| 职业角色 |
主要游戏职业 |
CustomRole, IListener |
Seer, Cleaner, Jester |
| 附加身份 |
额外身份效果 |
CustomRole, IListener |
Madman |
| 子身份 |
依附于主职业的技能 |
CustomRole, IListener |
DeathDeterrence |
| 未知角色 |
特殊用途占位 |
CustomRole |
Unknown |
注意:编写职业时,不需要声明他们的Name,ShortName以及Description,他们是根据语言系统自动获取的
这种分层的角色设计模式确保了代码的可维护性和扩展性,开发者可以根据具体需求选择合适的实现方式。
六、RPC(远程过程调用)系统
6.1 RPC系统概述
RPC系统是COG模组中用于实现多玩家同步的核心通信机制。该系统基于Among Us原生的RPC机制进行扩展,支持自定义RPC消息的发送、接收和处理。
6.2 核心枚举定义
6.2.1 已知RPC类型枚举 (KnownRpc)
- 位置: COG.Rpc.KnownRpc
- 功能: 定义所有自定义RPC消息的唯一标识符
- 枚举值:
public enum KnownRpc : uint
{
ShareRoles = 100, // 分享角色信息
HideDeadBody, // 隐藏尸体
UpdateOption, // 更新选项设置
SetRole, // 设置角色
Feedback, // 反馈信息
Revive, // 复活玩家
NotifySettingChange, // 通知设置变更
Mark, // 标记玩家
ShareOptions, // 分享选项配置
ClearSabotages, // 清除破坏
ShareWinners, // 分享胜利者
KillWithoutDeadBody, // 无尸体击杀
ShareAbilityOrVentUseForInspector, // 分享能力/通风管使用
SyncRoleGameData, // 同步角色游戏数据
DieWithoutAnimationAndBody, // 无动画死亡
SyncGameEvent, // 同步游戏事件
AdvancedMurder, // 高级击杀
SetSanity, // 设置理智值
PlayKillAnimation // 播放击杀动画
}
6.3 RPC处理器接口与实现
6.3.1 RPC处理器接口 (IRpcHandler)
- 位置: COG.Rpc.IRpcHandler
- 功能: 所有RPC处理器的基接口
- 主要属性:
- Handlers: 静态处理器集合,存储所有已注册的处理器
- OnReceive: 接收RPC消息时的回调委托
- 核心方法:
- Register(IRpcHandler handler): 注册处理器到全局集合
6.3.2 基础RPC处理器 (RpcHandler)
- 位置: COG.Rpc.RpcHandler
- 功能: 处理无参数的RPC消息
- 构造函数:
public RpcHandler(byte callId, Action onPerform)
public RpcHandler(KnownRpc callId, Action onPerform)
public RpcHandler(RpcCalls callId, Action onPerform)
- 主要方法:
- Perform(): 本地执行RPC逻辑
- Send(): 发送RPC消息到网络
- PerformAndSend(): 执行并发送(组合操作)
6.3.3 泛型RPC处理器
系统提供了一系列泛型RPC处理器,支持1到5个参数的消息处理:
- 处理器类型:
- RpcHandler<T>: 单参数处理器
- RpcHandler<T1, T2>: 双参数处理器
- RpcHandler<T1, T2, T3>: 三参数处理器
- RpcHandler<T1, T2, T3, T4>: 四参数处理器
- RpcHandler<T1, T2, T3, T4, T5>: 五参数处理器
- 通用模式:
- 每个泛型处理器都包含对应的构造函数重载
- Perform(T args): 带参数执行
- Send(T args): 带参数发送
- PerformAndSend(T args): 带参数执行并发送
6.4 RPC消息写入器 (RpcWriter)
6.4.1 消息写入方法
基础类型写入:
- Write(bool value): 写入布尔值
- Write(byte value): 写入字节
- Write(int value): 写入整数
- Write(float value): 写入浮点数
- Write(string value): 写入字符串
高级类型写入:
- WritePacked(int value): 写入压缩整数
- WriteBytesAndSize(byte[] bytes): 写入字节数组(带长度)
- WriteNetObject(InnerNetObject obj): 写入网络对象
- WriteVector2(Vector2 vec): 写入二维向量
6.4.2 消息发送控制
启动方法:
// 多种重载形式
public static RpcWriter Start(byte callId, PlayerControl[]? targets = null)
public static RpcWriter Start(KnownRpc callId, PlayerControl[]? targets = null)
public static RpcWriter Start(PlayerControl playerControl, KnownRpc callId, PlayerControl[]? targets = null)
完成发送:
快捷方法:
- StartAndSend(): 启动并立即发送的便捷方法
6.5 RPC监听器 (RpcListener)
6.5.1 核心处理方法
方法: AfterRpcReceived(PlayerHandleRpcEvent @event)
处理逻辑:
- 读取RPC调用ID并转换为KnownRpc枚举
- 根据不同的RPC类型执行相应的处理逻辑
- 调用注册的IRpcHandler处理器
- 通知所有自定义角色处理RPC消息
6.5.2 具体RPC处理逻辑
选项同步相关:
- UpdateOption: 更新单个选项设置
- ShareOptions: 批量同步所有选项配置
角色管理相关:
- SetRole: 为玩家设置自定义角色
- SyncRoleGameData: 同步角色特定的游戏数据
游戏逻辑相关:
- KillWithoutDeadBody: 执行无尸体击杀
- Revive: 复活玩家
- HideDeadBody: 隐藏尸体对象
- AdvancedMurder: 处理高级击杀选项
玩家标记系统:
游戏事件同步:
- SyncGameEvent: 同步自定义游戏事件记录
6.6 RPC工具类 (RpcUtils)
6.6.1 扩展方法
RPC发送快捷方法:
// 为PlayerControl添加的扩展方法
public static RpcWriter StartRpcImmediately(this PlayerControl playerControl, KnownRpc callId, PlayerControl[]? targets = null)
public static RpcWriter StartRpcImmediately(this PlayerControl playerControl, RpcCalls callId, PlayerControl[]? targets = null)
消息读取工具:
- ReadVector<T>(this MessageReader reader): 从消息读取器读取Vector2
- ReadPlayerControl(this MessageReader reader): 读取PlayerControl对象
6.7 RPC处理补丁 (RPCHandlerPatch)
6.7.1 补丁方法
位置: COG.Patch.RPCHandlerPatch
功能: 使用Harmony补丁拦截游戏原生的RPC处理
前缀处理 (Prefix):
- 在原始RPC处理前执行
- 触发PlayerHandleRpcEvent的前置处理器
- 返回布尔值控制是否继续执行原始方法
后缀处理 (Postfix):
- 在原始RPC处理后执行
- 记录RPC接收日志
- 触发PlayerHandleRpcEvent的后置处理器
6.8 RPC系统特点
6.8.1 类型安全
- 使用强类型枚举定义RPC消息
- 泛型处理器确保参数类型匹配
- 编译时类型检查减少运行时错误
6.8.2 灵活扩展
- 支持1-5个参数的泛型处理器
- 易于添加新的RPC类型
- 模块化的处理器注册机制
6.8.3 性能优化
- 消息压缩支持减少网络流量
- 批量操作减少RPC调用次数
- 目标选择机制优化网络传输
6.8.4 调试支持
- 详细的RPC发送/接收日志
- 目标玩家列表可视化
- 错误处理和异常捕获
RPC系统为COG模组提供了可靠的多玩家数据同步能力,是实现复杂游戏逻辑和角色能力的基础通信框架。