API 文档
公开 API 按模块列出。接入说明见 SDK 开发文档。
概述
| 模块 | 类型 |
| 框架 | FrameworkEntry、FrameworkBootstrap、ServiceLocator、IEventBus、ISceneService、ITimerService、ITimeService、ICoroutineRunner、IResourceService、ILogService、BootSystem |
| 管控 | ContentStateSync、CalibrationHandler、IPDAutoCalibrator |
| 大空间 | ExperienceAreaHandler、DetectingSystem、ExperienceAreaSafetyPresenter、ExperienceAreaItem |
| 内容 | Enums、ExperienceAreaIdAttribute、ContentSceneSearcher、ContentSceneDirectorSample、RoomContentSceneFlow、ContentProgressReporter |
| 网络 | RoomNetClient、RoomMgr、EventBroadcastHandler、CustomMessageHandler、NetworkedObject、ObjectSyncHandler、MemberHandler、TransformHandler、ContentSyncHandler、AnimationSyncHandler、TimeSyncHandler、AvatarMgr、AvatarMono |
| 交互 | HandGesturesMgr、HandGestureHold、CustomGazeInteractor |
框架
FrameworkEntry
| API | 说明 |
void FrameworkEntry.Awake() | 入口自动调 FrameworkBootstrap.InitFramework();Inspector nextScene 可空 |
FrameworkBootstrap
| API | 说明 |
void FrameworkBootstrap.InitFramework() | 注册基础服务(Entry 会自动调) |
ServiceLocator
| API | 说明 |
void ServiceLocator.Register<T>(T service) | 注册服务 |
T ServiceLocator.Get<T>() | 取服务,未注册抛异常 |
bool ServiceLocator.TryGet<T>(out T service) | 取服务,未注册不抛 |
IEventBus
| API | 说明 |
void IEventBus.Subscribe(int id, Action<GameEventArg> listener) | 订阅本地事件 |
void IEventBus.Unsubscribe(int id, Action<GameEventArg> listener) | 取消订阅,须同一委托 |
void IEventBus.Publish(int id, Action<GameEventArg> setupArgs = null) | 发布 |
GameEventArg IEventBus.GetArgs(int id) | 取事件参数对象 |
ISceneService
| API | 说明 |
void ISceneService.LoadSceneAsync(string sceneName, LoadSceneMode mode = Single, Action<float> onProgress = null, Action onCompleted = null) | mode:Single 卸当前 / Additive 叠加;onProgress 0~1 |
void ISceneService.UnloadSceneAsync(string sceneName, Action<float> onProgress = null, Action onCompleted = null) | 异步卸载 |
ITimerService / ITimerHandle
| API | 说明 |
ITimerHandle ITimerService.Wait(float seconds, Action callback, bool useUnscaledTime = false) | 延迟回调 |
ITimerHandle ITimerService.WaitFrame(int frameCount, Action callback) | 延迟 N 帧 |
ITimerHandle ITimerService.Repeat(float intervalSeconds, Action callback, int repeatCount = -1, bool immediate = false, bool useUnscaledTime = false) | 重复;repeatCount < 0 无限 |
ITimerHandle ITimerService.RepeatFrame(int intervalFrames, Action callback, int repeatCount = -1, bool immediate = false) | 按帧重复 |
bool ITimerHandle.IsDone { get; } | 是否已结束 |
void ITimerHandle.Cancel() | 取消定时器 |
ITimeService
| API | 说明 |
float ITimeService.DeltaTime { get; } | 缩放后 delta |
float ITimeService.UnscaledDeltaTime { get; } | 未缩放 delta |
float ITimeService.Time { get; } | 缩放后时间 |
float ITimeService.UnscaledTime { get; } | 未缩放时间 |
float ITimeService.TimeScale { get; set; } | 时间缩放 |
ICoroutineRunner
| API | 说明 |
Coroutine ICoroutineRunner.Run(IEnumerator routine) | 开协程 |
void ICoroutineRunner.Stop(Coroutine coroutine) | 停一个 |
void ICoroutineRunner.StopAll() | 停全部 |
IResourceService
| API | 说明 |
T IResourceService.LoadAsset<T>(string location) | 同步加载 |
void IResourceService.LoadAssetAsync<T>(string location, Action<T> onCompleted) | 异步加载 |
void IResourceService.UnloadAsset(UnityEngine.Object asset) | 卸载资源 |
ILogService
| API | 说明 |
void ILogService.Log(string context, string message) | 日志 |
void ILogService.Warning(string context, string message) | 警告 |
void ILogService.Error(string context, string message) | 错误 |
BootSystem
| API | 说明 |
string BootSystem.DeviceSn { get; } | 设备 SN |
void BootSystem.SetDeviceSn(string sn) | 设置设备 SN |
ContentMode BootSystem.ContentMode { get; } | LargeSpace / Origin |
RunningMode BootSystem.RunningMode { get; } | 运行模式 |
BootConfigRoot BootSystem.Root { get; } | 已解析的 boot 配置 |
string BootSystem.EditorMapConfigUrl { get; } | Editor 地图 JSON 路径 |
string BootSystem.ResolveBootConfigPath() | 当前 boot 文件路径 |
bool BootSystem.StoragePermissionReady { get; } | 存储权限是否就绪 |
bool BootSystem.BindToBServer { get; } | 是否已绑定管控服务 |
void BootSystem.RegisterFocus(UnityAction<bool> onFocus) | 环境纹理检测焦点回调 |
void BootSystem.UnRegisterFocus(UnityAction<bool> onFocus) | 取消焦点回调 |
int BootSystem.GotoEnvironmentTextureCheck() | 进入环境纹理检测 |
if (!ServiceLocator.TryGet<ISceneService>(out var scenes)) return;
scenes.LoadSceneAsync("Level_A", LoadSceneMode.Additive, onCompleted: () => { });
if (!ServiceLocator.TryGet<ITimerService>(out var timer)) return;
var handle = timer.Wait(30f, () => { /* 超时 */ });
handle.Cancel();
if (!ServiceLocator.TryGet<IEventBus>(out var bus)) return;
bus.Subscribe(100, _ => { });
bus.Publish(100);
string sn = BootSystem.Instance.DeviceSn;
管控
ContentStateSync
| API | 说明 |
bool autoSync | 勾选:校准后自动同步,并本地置 Running。等管控开播须取消,自己调 StartSync |
ContentStatus ContentStateSync.ContentStatus { get; } | 当前内容状态 |
RoomData ContentStateSync.Room { get; } | 房间分配数据 |
bool ContentStateSync.IsLateJoiner { get; } | 进房时房间已 Running(中途加入) |
void ContentStateSync.StartSync() | 开始握手 / 上报 / 连房间;不是开播。autoSync 未勾选时须内容自己调 |
void ContentStateSync.StopSync() | 停止上报 |
void ContentStateSync.SetContentProgress(int progress, string progressNode) | 只写进度 0~100,不上报 |
void ContentStateSync.SetContentProgressAndReport(int progress, string progressNode) | 写进度并立即上报 |
void ContentStateSync.NotifyExperienceStarted() | 本地 Ready → Running(无管控开播时) |
void ContentStateSync.NotifyAgreementFinished() | 打开体验计时:已 Running 且调过它才开始计时;不调时长为 0 |
void ContentStateSync.NotifyCalibrationFinished() | 校准完成 → Ready |
void ContentStateSync.NotifyGameFinished(JsonData payload = null) | 上报结束;payload 默认可空 |
bool ContentStateSync.TryGetPlayerName(string sn, out string nickName) | 按设备 SN 取昵称 |
ContentStatus
| 值 | 说明 |
Unknown = -1 | 未知 |
Connected = 0 | 已握手 |
Calibration = 100 | 校准中 |
Ready = 200 | 就绪(可接收开播) |
Running = 300 | 已开播 |
Shutdown = 400 | 结束 |
CalibrationHandler
| API | 说明 |
CalibrationState CalibrationHandler.CalibrationState { get; } | UnCalibration / Calibration / CalibrationEnd |
IPDAutoCalibrator
| API | 说明 |
void IPDAutoCalibrator.EnableIPDAdjustment() | 开启音量键 IPD 调节 |
contentStateSync.StartSync();
director.GoTo(ContentSceneSearcher.佩戴区);
if (!contentStateSync.IsLateJoiner)
yield return new WaitUntil(() =>
contentStateSync.ContentStatus == ContentStatus.Running);
contentStateSync.NotifyAgreementFinished();
director.GoTo(ContentSceneSearcher.内容1);
大空间
ExperienceAreaHandler
| API | 说明 |
void ExperienceAreaHandler.LoadBoundaryPlace() | 按 Boot 实例化体验区 |
bool ExperienceAreaHandler.SwitchExperienceArea(string areaId, bool deactivateOthers = true, bool alignContentRoot = true) | 切换当前区 |
bool ExperienceAreaHandler.SwitchToNextExperienceArea(bool loop = false, bool alignContentRoot = true) | 按顺序切下一区 |
bool ExperienceAreaHandler.ShowExperienceAreaPreview(string areaId) | 预览指定区边界,不改当前区 |
bool ExperienceAreaHandler.ShowNextExperienceArea(bool loop = false) | 预览下一区 |
void ExperienceAreaHandler.ClearExperienceAreaPreview() | 清除预览 |
void ExperienceAreaHandler.SetContentRoot(GameObject root) | 指定内容根 |
void ExperienceAreaHandler.AlignContentRootToActiveArea() | 把根对齐到当前区 |
string ExperienceAreaHandler.GetNextExperienceAreaId(bool loop = false) | 下一区 id,没有则 null |
ExperienceAreaItem ExperienceAreaHandler.GetArea(string id) | 取区实例,没有则 null |
ExperienceAreaItem ExperienceAreaHandler.ExperienceAreaItem { get; } | 当前体验区实例 |
ExperienceAreaItem ExperienceAreaHandler.PreviewArea { get; } | 当前预览区实例 |
bool ExperienceAreaHandler.IsBoundaryReady { get; } | 场地是否就绪 |
string ExperienceAreaHandler.ActiveAreaId { get; } | 当前体验区 id |
string ExperienceAreaHandler.PreviewAreaId { get; } | 当前预览区 id |
bool ExperienceAreaHandler.CameraMaskLocked { get; } | 相机 mask 是否锁定 |
void ExperienceAreaHandler.LockCameraMask(bool locked) | 锁定后 Safety 不再改 mask |
void ExperienceAreaHandler.SetCameraLayerMask(bool boundaryMask) | true 出区 mask,false 默认 mask |
void ExperienceAreaHandler.SetCameraLayerMask(LayerMask layerMask) | 直接指定 mask |
event Action<ExperienceAreaChange> ExperienceAreaHandler.OnAreaChanged | 切区;FromId / ToId |
event Action<ExperienceAreaChange> ExperienceAreaHandler.OnPreviewChanged | 预览变化 |
var h = GetComponent<ExperienceAreaHandler>();
h.LoadBoundaryPlace();
h.SetContentRoot(root);
bool ok = h.SwitchExperienceArea("area_01");
h.ShowExperienceAreaPreview("area_02");
h.OnAreaChanged += e => { /* e.FromId, e.ToId */ };
DetectingSystem
| API | 说明 |
void DetectingSystem.EnableDetecting() | 开始检测 |
void DetectingSystem.DisableDetecting() | 停止检测并清空当前区 |
void DetectingSystem.RegisterHeadDetecting(UnityAction<RunningContentData> callback) | 头部位姿检测回调 |
void DetectingSystem.UnRegisterHeadDetecting(UnityAction<RunningContentData> callback) | 取消,须同一委托 |
bool DetectingSystem.IsInObstacle() | 是否在障碍内 |
List<ExperienceAreaItem> DetectingSystem.ContentArea { get; } | 头部当前所在内容区 |
List<GameObject> DetectingSystem.HexRoad { get; } | 当前 Hex 通道 |
List<GameObject> DetectingSystem.Obstacles { get; } | 当前障碍 |
RunningContentData
| API | 说明 |
int RunningContentData.isOutContentArea | 1 出区,0 在区内 |
string RunningContentData.currentAreas | 当前区名,逗号拼接 |
DetectingSystem.Instance.EnableDetecting();
DetectingSystem.Instance.RegisterHeadDetecting(data => {
bool outArea = data.isOutContentArea == 1;
string areas = data.currentAreas;
});
bool inObstacle = DetectingSystem.Instance.IsInObstacle();
ExperienceAreaSafetyPresenter
| API | 说明 |
bool ExperienceAreaSafetyPresenter.CameraMaskLocked { get; } | 相机 mask 是否锁定 |
void ExperienceAreaSafetyPresenter.LockCameraMask(bool locked) | 锁定后不再自动改 mask |
void ExperienceAreaSafetyPresenter.SetCameraLayerMask(bool boundaryMask) | true 出区 mask,false 默认 mask |
void ExperienceAreaSafetyPresenter.SetCameraLayerMask(LayerMask layerMask) | 直接指定 mask |
ExperienceAreaItem
| API | 说明 |
bool ExperienceAreaItem.IsOutAreaVisible { get; } | 出区线是否显示 |
void ExperienceAreaItem.SetOutAreaVisible(bool show) | 显示出区线 |
void ExperienceAreaItem.SetGuideVisible(bool show) | 显示引导 |
void ExperienceAreaItem.SetObstacleVisualInObstacle(bool inObstacle) | 障碍内视觉 |
PlaceItem ExperienceAreaItem.PlaceItem { get; } | 该区 place 数据 |
var area = h.GetArea(h.ActiveAreaId);
area.SetOutAreaVisible(true);
area.SetGuideVisible(true);
h.SetCameraLayerMask(true);
h.LockCameraMask(true);
边界标记
| 类型 | 说明 |
ExperienceHexRoadMarker | Hex 通道检测 |
ExperienceObstacleMarker | 障碍检测 |
ExperienceNearAreaLineMarker | 近区线 |
ExperienceOutAreaLineMarker | 出区线 |
ExperienceObstacleAreaMarker | 障碍区视觉 |
ExperienceBoundaryVisualMarker | 子视觉;Kind:Boundary / Arrow / GuideLine |
内容
Enums
| API | 说明 |
string Enums.GetDescByEnum(this Enum value) | 读 [Description],可作场景名 |
string Enums.GetAreaIdByEnum(this Enum value) | 读 [ExperienceAreaId];无标注返回 "" |
T Enums.GetAttributeOfType<T>(this Enum enumVal) | 读任意特性 |
T Enums.GetValueByIndex<T>(int index) | 按下标取枚举值 |
int Enums.GetIndexByValue<T>(T enumVal) | 取枚举下标 |
T Enums.GetEnumByDescription<T>(string description) | 按 Description 反查枚举 |
ExperienceAreaIdAttribute
| API | 说明 |
ExperienceAreaIdAttribute(string areaId) | 标在枚举字段上,值为 Boot placeItems.id |
string ExperienceAreaIdAttribute.AreaId { get; } | 体验区 id |
public enum MyStep {
[Description("Level_Wear")]
[ExperienceAreaId("area_01")]
Wear,
}
string scene = MyStep.Wear.GetDescByEnum();
string area = MyStep.Wear.GetAreaIdByEnum();
ContentSceneSearcher / ContentSceneStepMap
| API | 说明 |
ContentSceneSearcher.佩戴区 / 内容1 / 内容2 / 归还区 | 示例步骤;Description=场景名,ExperienceAreaId=areaId |
string ContentSceneStepMap.GetSceneName(ContentSceneSearcher step) | 场景名;空字符串表示本步不加载场景 |
string ContentSceneStepMap.GetAreaId(ContentSceneSearcher step) | 体验区 id |
string scene = ContentSceneStepMap.GetSceneName(ContentSceneSearcher.内容1); // Level_B
string area = ContentSceneStepMap.GetAreaId(ContentSceneSearcher.内容1); // area_02
ContentSceneDirectorSample
| API | 说明 |
void ContentSceneDirectorSample.GoTo(ContentSceneSearcher step, bool forceReload = false) | 进入步骤:有场景则加载,再切体验区;无场景只切区 |
void ContentSceneDirectorSample.NextContent() | 下一步 |
void ContentSceneDirectorSample.PrevContent() | 上一步 |
void ContentSceneDirectorSample.SwitchToNextExperienceArea() | 切下一体验区 |
void ContentSceneDirectorSample.ShowNextExperienceAreaPreview() | 预览下一区 |
void ContentSceneDirectorSample.ClearExperienceAreaPreview() | 清除预览 |
void ContentSceneDirectorSample.StartAutoCycleExperienceAreas() | 自动循环步骤(联调用) |
void ContentSceneDirectorSample.StopAutoCycleExperienceAreas() | 停止自动循环 |
ContentSceneSearcher ContentSceneDirectorSample.CurrentStep { get; } | 当前步骤 |
string ContentSceneDirectorSample.LoadedContentScene { get; } | 已加载的内容场景名 |
bool ContentSceneDirectorSample.IsBusy { get; } | 是否正在切步 |
event Action<ContentSceneSearcher> ContentSceneDirectorSample.OnContentStepChanged | 步骤变化 |
var director = GetComponent<ContentSceneDirectorSample>();
director.GoTo(ContentSceneSearcher.内容1);
director.NextContent();
director.OnContentStepChanged += step => { };
RoomContentSceneFlow
| API | 说明 |
void RoomContentSceneFlow.ClientRequestNextContent(ContentSceneSearcher step) | 请求切内容步骤 |
void RoomContentSceneFlow.ClientRequestNextExperienceArea(string areaId) | 请求切体验区 |
void RoomContentSceneFlow.SetSceneStep(ContentSceneSearcher step, bool notify = true) | 写入当前步骤 |
void RoomContentSceneFlow.SetExperienceAreaStep(string areaId, bool notify = true) | 写入当前体验区 |
ContentSceneSearcher RoomContentSceneFlow.SceneStep { get; } | 当前步骤 |
string RoomContentSceneFlow.ExperienceAreaId { get; } | 当前体验区 id |
event Action<ContentSceneSearcher> RoomContentSceneFlow.OnSceneStepChanged | 步骤确认 |
event Action<string> RoomContentSceneFlow.OnExperienceAreaStepChanged | 体验区确认 |
var flow = RoomContentSceneFlow.Instance;
flow.OnSceneStepChanged += step => director.GoTo(step);
flow.ClientRequestNextContent(ContentSceneSearcher.内容1);
flow.ClientRequestNextExperienceArea("area_02");
ContentProgressReporter
| API | 说明 |
void ContentProgressReporter.OnContentStepChanged(ContentSceneSearcher step) | 切步后重算本段进度 |
void ContentProgressReporter.OnExperienceAreaChanged(string areaId) | 更新 progressNode |
void ContentProgressReporter.ResetProgress() | 进度归零 |
void ContentProgressReporter.SetSnapSegmentProgress(bool enabled) | 快进:离段记满,段内不按时长涨 |
int ContentProgressReporter.GlobalProgressPct { get; } | 整局 0~100 |
bool ContentProgressReporter.GameFinished { get; } | 是否已到 100% 并上报结束 |
reporter.OnContentStepChanged(ContentSceneSearcher.内容1);
int pct = reporter.GlobalProgressPct;
reporter.ResetProgress();
网络
RoomNetClient
| API | 说明 |
void RoomNetClient.Configure(string ip, int port, string roomKey = null) | 写入地址,不自动连 |
void RoomNetClient.Connect() | 发起连接 |
void RoomNetClient.Disconnect() | 断开 |
RoomNetStatus RoomNetClient.ConnectStatus { get; } | Initialize / Connecting / Connected / Disconnected / Stopped |
bool RoomNetClient.IsConnected { get; } | 是否已连上 |
bool RoomNetClient.IsServerConfigured { get; } | IP 与端口是否已配 |
int RoomNetClient.LocalPlayerId { get; } | 本端玩家 Id,未就绪 -1 |
RoomMember RoomNetClient.Self { get; } | 本端成员 |
string RoomNetClient.ServerIp { get; } | 房间服务 IP |
int RoomNetClient.ServerPort { get; } | 房间服务端口 |
event Action RoomNetClient.OnRoomConnected | 连上 |
event Action RoomNetClient.OnRoomDisconnected | 断开 |
RoomNetClient.Instance.Configure("192.168.x.x", 11001);
RoomNetClient.Instance.Connect();
RoomNetClient.Instance.OnRoomConnected += () => { };
int self = RoomNetClient.Instance.LocalPlayerId;
RoomMgr
| API | 说明 |
RoomNetClient RoomMgr.RoomNetClient { get; } | 房间连接 |
EventBroadcastHandler RoomMgr.EventBroadcastHandler { get; } | 房间事件广播 |
MemberHandler RoomMgr.MemberHandler { get; } | 成员列表 |
TransformHandler RoomMgr.TransformHandler { get; } | 头手位姿 |
ObjectSyncHandler RoomMgr.ObjectSyncHandler { get; } | 物体同步 |
void RoomMgr.RegisterObject(NetworkedObject networkedObject) | 注册场景物体 |
void RoomMgr.RegisterPrefab(string prefabName, GameObject prefab) | 注册生成用预制体 |
uint RoomMgr.SpawnObject(string goName, Vector3 pos, Quaternion rot, Vector3 scale, string customData) | goName 对应已注册预制体名 |
void RoomMgr.RequestOwnership(uint id, bool force) | 按 objectId 申请所有权 |
void RoomMgr.ReleaseOwnership(uint id) | 释放所有权 |
void RoomMgr.CleanupRoomState() | 清房间状态(断线时会调) |
event Action RoomMgr.OnRoomStateCleaned | 房间状态已清理 |
EventBroadcastHandler
| API | 说明 |
void EventBroadcastHandler.RegisterEvent(ushort eventId, UnityAction<int, byte[]> listener) | 注册;senderId 为触发方玩家 Id,payload 可空 |
void EventBroadcastHandler.RegisterStringEvent(ushort eventId, UnityAction<int, string> listener) | 字符串 payload |
void EventBroadcastHandler.RegisterJsonEvent<T>(ushort eventId, UnityAction<int, T> listener) | JSON payload |
void EventBroadcastHandler.RegisterSimpleEvent(ushort eventId, UnityAction<int> listener) | 无 payload |
void EventBroadcastHandler.TriggerEvent(ushort eventId, byte[] payload = null) | 发送字节 |
void EventBroadcastHandler.TriggerEventString(ushort eventId, string data) | 发送字符串 |
void EventBroadcastHandler.TriggerEventJson<T>(ushort eventId, T obj) | 发送 JSON |
void EventBroadcastHandler.TriggerEventSimple(ushort eventId) | 无 payload 发送 |
void EventBroadcastHandler.UnregisterEvent(ushort eventId, UnityAction<int, byte[]> listener) | 取消注册 |
void EventBroadcastHandler.RegisterGlobalListener(UnityAction<int, ushort, byte[]> listener) | 监听全部 eventId |
void EventBroadcastHandler.UnregisterGlobalListener(UnityAction<int, ushort, byte[]> listener) | 取消全局监听 |
bool EventBroadcastHandler.IsEventRegistered(ushort eventId) | 该 eventId 是否已注册 |
event Action<int, ushort, byte[]> EventBroadcastHandler.OnEventReceived | 收到任意事件 |
自定义 eventId 服务器只转发。101 / 104:同等人数、相同 payload 后回 201 / 204。
var eb = RoomMgr.Instance.EventBroadcastHandler;
eb.RegisterEvent(1001, (senderId, payload) => {
bool fromSelf = senderId == RoomNetClient.Instance.LocalPlayerId;
});
eb.TriggerEvent(1001, myBytes);
eb.TriggerEventString(1002, "hello");
eb.TriggerEventJson(1003, dto);
eb.TriggerEventSimple(1004);
CustomMessageHandler
| API | 说明 |
void CustomMessageHandler.RegisterChannel(ushort channelId, UnityAction<int, byte[]> handler) | 注册频道 |
void CustomMessageHandler.UnregisterChannel(ushort channelId) | 取消频道 |
bool CustomMessageHandler.IsChannelRegistered(ushort channelId) | 频道是否已注册 |
void CustomMessageHandler.SendReliable(ushort channelId, byte[] data) | 可靠发送 |
void CustomMessageHandler.SendUnreliable(ushort channelId, byte[] data) | 不可靠发送 |
void CustomMessageHandler.SendStringReliable(ushort channelId, string message) | 可靠字符串 |
void CustomMessageHandler.SendStringUnreliable(ushort channelId, string message) | 不可靠字符串 |
void CustomMessageHandler.SendJsonReliable<T>(ushort channelId, T obj) | 可靠 JSON |
void CustomMessageHandler.SendJsonUnreliable<T>(ushort channelId, T obj) | 不可靠 JSON |
var cm = GetComponent<CustomMessageHandler>();
cm.RegisterChannel(10, (senderId, data) => { });
cm.SendReliable(10, bytes);
cm.SendStringReliable(10, "hello");
NetworkedObject
| API | 说明 |
uint NetworkedObject.ObjectId { get; } | 物体 Id;场景 ≥ 1000,运行时 Spawn ≥ 1_000_000 |
bool NetworkedObject.HasValidId { get; } | Id 是否有效 |
void NetworkedObject.BindObjectId(uint id) | 绑定运行时 Id |
void NetworkedObject.RequestOwnership(bool force) | false 无人占用时申请;true 抢占 |
bool NetworkedObject.IsOwner() | 本端是否 Owner |
bool NetworkedObject.HasOwner() | 是否已有人持有 |
void NetworkedObject.SyncNow() | 立即同步 |
void NetworkedObject.SetCustomData(byte[] data) | 附加自定义数据 |
byte[] NetworkedObject.GetCustomData() | 读取自定义数据 |
UnityEvent NetworkedObject.onOwnerChanged | 所有权变化 |
NetworkedObjectId
| API | 说明 |
uint NetworkedObjectId.AllocateRuntimeId() | 运行时发号,≥ 1_000_000 |
ObjectSyncHandler
| API | 说明 |
void ObjectSyncHandler.RequestOwnership(uint objectId, bool force) | 按 Id 申请所有权 |
bool ObjectSyncHandler.IsOwner(uint objectId, int playerId) | 指定玩家是否 Owner |
int ObjectSyncHandler.GetOwner(uint objectId) | 当前 Owner 玩家 Id |
void ObjectSyncHandler.DestroyNetworkedObject(uint objectId) | 销毁网络物体 |
event Action<uint, GameObject> ObjectSyncHandler.OnObjectSpawned | 物体已生成 |
event Action<uint> ObjectSyncHandler.OnObjectDestroyed | 物体已销毁 |
event Action<uint, int, int> ObjectSyncHandler.OnOwnershipChanged | 所有权变化 (id, old, new) |
netObj.RequestOwnership(false);
if (netObj.IsOwner()) netObj.SyncNow();
RoomMgr.Instance.RegisterPrefab("MyProp", prefab);
uint id = RoomMgr.Instance.SpawnObject("MyProp", pos, rot, scale, "{}");
MemberHandler
| API | 说明 |
void MemberHandler.RegisterHandler(UnityAction<List<RoomMember>> action) | 成员列表变化 |
void MemberHandler.UnRegisterHandler(UnityAction<List<RoomMember>> action) | 取消,须同一委托 |
void MemberHandler.ClearMembers() | 清空成员 |
RoomMember
| API | 说明 |
int RoomMember.PlayerId | 房间玩家 Id |
string RoomMember.DeviceSn | 设备 SN |
TransformHandler
| API | 说明 |
void TransformHandler.RegisterHandler(UnityAction<PlayerTransformMsg> action) | 头手位姿回调 |
void TransformHandler.UnRegisterHandler(UnityAction<PlayerTransformMsg> action) | 取消,须同一委托 |
void TransformHandler.TryFlushPending(int playerId, AvatarMono mono) | 把缓存位姿刷到 Avatar |
void TransformHandler.ClearPending() | 清空缓存位姿 |
var mh = RoomMgr.Instance.MemberHandler;
mh.RegisterHandler(list => {
foreach (var m in list) { /* m.PlayerId, m.DeviceSn */ }
});
ContentSyncHandler
| API | 说明 |
void ContentSyncHandler.RegisterContent(string contentId, IContentController controller) | 注册播控 |
void ContentSyncHandler.UnregisterContent(string contentId) | 取消注册 |
bool ContentSyncHandler.IsContentRegistered(string contentId) | 是否已注册 |
void ContentSyncHandler.Play(string contentId, float seekTime = 0f) | 全房播放 |
void ContentSyncHandler.Pause(string contentId) | 暂停 |
void ContentSyncHandler.Stop(string contentId) | 停止 |
void ContentSyncHandler.Seek(string contentId, float seekTime) | 跳转到 seekTime 秒 |
float ContentSyncHandler.GetProgress(string contentId) | 播放进度 0~1 |
float ContentSyncHandler.GetPlaybackTime(string contentId) | 当前播放时间 |
event Action<ContentSyncMsg> ContentSyncHandler.OnContentSynced | 收到同步 |
event Action<string, ContentState> ContentSyncHandler.OnContentStateChanged | 状态变化 |
IContentController
| API | 说明 |
void IContentController.ApplySyncState(ContentSyncMsg msg) | 应用同步状态 |
float IContentController.GetCurrentTime() | 当前播放时间 |
float IContentController.GetDuration() | 总时长 |
ContentState IContentController.GetCurrentState() | Idle / Loading / Playing / Paused / Stopped / Finished |
var cs = GetComponent<ContentSyncHandler>();
cs.RegisterContent("intro_video", myVideo);
cs.Play("intro_video", 0f);
cs.Seek("intro_video", 12.5f);
AnimationSyncHandler / NetworkedAnimator
| API | 说明 |
void AnimationSyncHandler.RegisterAnimator(int playerId, NetworkedAnimator networkedAnimator) | 注册动画同步 |
void AnimationSyncHandler.UnregisterAnimator(int playerId) | 取消注册 |
void NetworkedAnimator.ForceSyncAnimation() | 立即同步当前动画 |
void NetworkedAnimator.SetPlayerId(int id) | 绑定玩家 Id |
TimeSyncHandler
| API | 说明 |
bool TimeSyncHandler.IsSynced { get; } | 是否已对时 |
long TimeSyncHandler.ServerTimeMs { get; } | 估算的服务器时间 |
void TimeSyncHandler.RequestTimeSync() | 请求对时 |
long TimeSyncHandler.LocalToServerTime(long localTimeMs) | 本地 → 服务器时间 |
long TimeSyncHandler.ServerToLocalTime(long serverTimeMs) | 服务器 → 本地时间 |
AvatarMgr
| API | 说明 |
void AvatarMgr.SetCatalog(AvatarCatalog catalog) | 设置形象目录 |
AvatarCatalog AvatarMgr.Catalog { get; } | 当前目录 |
AvatarMono AvatarMgr.GetAvatarRoom(int playerId) | 按玩家 Id 取 |
AvatarMono AvatarMgr.GetAvatarRoomFast(int playerId) | 按玩家 Id 快取 |
AvatarMono AvatarMgr.GetOrCreateRoom(string sn) | 按设备 SN 取或创建房间形象 |
AvatarMono AvatarMgr.GetOrCreateLobby(string sn, string id = "") | 大厅形象 |
AvatarMono AvatarMgr.Create(string id = null) | 按 catalog id 实例化 |
void AvatarMgr.BindRoomAvatarPlayerId(int playerId, AvatarMono mono) | 绑定玩家 Id |
void AvatarMgr.RemoveRoomAvatar(string sn, int playerId) | 移除房间形象 |
void AvatarMgr.ClearAllRoomAvatars() | 清空房间形象 |
AvatarMono
| API | 说明 |
void AvatarMono.SetMember(RoomMember member) | 绑定房间成员 |
void AvatarMono.SetDeviceSn(string sn) | 绑定设备 SN |
void AvatarMono.SetNickName(string nickName) | 设置昵称 |
void AvatarMono.Calibrate() | 校准 IK(需实现 IAvatarIkDriver) |
void AvatarMono.FadeOnline(bool online) | 在线淡入 / 离线淡出 |
bool AvatarMono.LeftHandTracked { get; } | 远端左手是否在跟踪 |
bool AvatarMono.RightHandTracked { get; } | 远端右手是否在跟踪 |
RoomMember? AvatarMono.RoomMember { get; } | 绑定的成员 |
IAvatarIkDriver
| API | 说明 |
void IAvatarIkDriver.Calibrate() | 全身 IK 校准 |
float IAvatarIkDriver.LeftHandWeight { get; set; } | 左手 IK 权重 |
float IAvatarIkDriver.RightHandWeight { get; set; } | 右手 IK 权重 |
AvatarCatalog
| API | 说明 |
bool AvatarCatalog.TryResolve(string avatarId, out AvatarData data, out AvatarMono prefab) | 按 id 解析形象 |
AvatarMono AvatarCatalog.GetPrefab(string avatarId) | 取预制体 |
AvatarMgr.Instance.SetCatalog(myCatalog);
var av = AvatarMgr.Instance.GetAvatarRoom(playerId);
av.SetNickName("P1");
av.Calibrate();
LobbyDeviceOnlineMonitor
| API | 说明 |
bool LobbyDeviceOnlineMonitor.IsOnline(string sn, long nowMs) | 大厅设备是否在线 |
event Action<string, bool> LobbyDeviceOnlineMonitor.OnOnlineChanged | 在线状态变化 (sn, online) |
交互
HandGesturesMgr
| API | 说明 |
bool HandGesturesMgr.LeftHandTracking { get; } | 左手是否在跟踪 |
bool HandGesturesMgr.RightHandTracking { get; } | 右手是否在跟踪 |
void HandGesturesMgr.RegisterLeftHandTrackingEvent(UnityAction acquired, UnityAction lost) | 左手获得 / 丢失跟踪 |
void HandGesturesMgr.UnRegisterLeftHandTrackingEvent(UnityAction acquired, UnityAction lost) | 取消,须同一对委托 |
void HandGesturesMgr.RegisterRightHandTrackingEvent(UnityAction acquired, UnityAction lost) | 右手获得 / 丢失跟踪 |
void HandGesturesMgr.UnRegisterRightHandTrackingEvent(UnityAction acquired, UnityAction lost) | 取消右手 |
HandGesturesMgr.Instance.RegisterLeftHandTrackingEvent(
() => { /* acquired */ },
() => { /* lost */ });
HandGestureHold
| API | 说明 |
void HandGestureHold.Register() | 开始检测手势 |
void HandGestureHold.Unregister() | 停止检测 |
UnityEvent HandGestureHold.gesturePerformed | 手势达成 |
UnityEvent HandGestureHold.gestureHold | 持续保持 |
UnityEvent<float> HandGestureHold.gestureHoldWithTime | 保持时长(秒) |
UnityEvent HandGestureHold.gestureEnded | 手势结束 |
float HandGestureHold.minimumHoldTime { get; set; } | 最短保持时间 |
hold.Register();
hold.gesturePerformed.AddListener(() => { });
hold.gestureEnded.AddListener(() => { });
CustomGazeInteractor
| API | 说明 |
bool CustomGazeInteractor.HasHit { get; } | 是否命中 |
Vector3 CustomGazeInteractor.HitPoint { get; } | 命中点 |
Vector3 CustomGazeInteractor.HitNormal { get; } | 命中法线 |
Action<IXRHoverInteractable> CustomGazeInteractor.onDwellTriggered | 凝视触发 |
交互组件
| 类型 | 说明 |
CustomGrabInteractor | 抓取 |
CustomGrabArea | 抓取区域 |
HandJointTracker | 手关节跟踪 |
HandJointFollower | 物体跟随关节 |
HandTag | 左手 / 右手标记 |