Skip to content

Unity 对接指南

This content is not available in your language yet.

本页面向已经完成 Unity 安装 的游戏项目。它不是最短验证路径;如果你只是第一次跑通 SDK,请先看 Unity Quick Start

  1. 在场景中保留唯一的 IGPRuntimeManager
  2. Assets/IGP/IGPConfig.asset 填写 appId
  3. 游戏启动流程主动调用 await runtimeManager.InitializeAsync()
  4. 按目标能力判断连接状态:桌面能力看 IsDesktopSessionAttached,房间能力看 onRoomJoinedIsHostedSessionAttached
  5. 再接入正版校验、成就、房间、实时消息、状态或 RPC。

常规接入不要求游戏手动填写运行目录或可执行文件路径。Desktop Executable Path Debug Override 只用于模拟正式安装路径或排查 exe 绑定问题,填写的是游戏自己的 Windows 可执行文件路径,不是桌面客户端路径。

参数位置是否必填含义
appIdIGPConfig必填IGP 为当前游戏分配的应用 ID。Unity 接入里最重要的配置,桌面能力、正版校验、成就和房间启动都会用它确认游戏身份。
sdkEnvironmentIGPConfig可选SDK 连接的桌面端环境。正式发布保持 PROD;预览联调可按团队要求使用 PREVIEW;本地开发调试才使用 DEV
debugLoggingIGPConfig可选打印 hosted session、KCP、P2P、Mirror Transport 等诊断日志。排查时开启,正式发布建议关闭。
desktopSessionAutoAttachIGPConfig通常保持默认是否在初始化时自动附着 desktop session。常规接入保持默认开启。
desktopExecutablePathDebugOverrideIGPConfig可选仅用于 Editor 调试特殊路径绑定。留空时 SDK 会按环境自动找对应桌面端。
desktopLaunchCommandIGPConfig可选仅用于 DEV 环境特殊调试,不是常规接入项。
using UnityEngine;
using IGP.UnitySDK;
public sealed class IGPGameBootstrap : MonoBehaviour
{
[SerializeField] private IGPRuntimeManager runtimeManager;
private async void Start()
{
runtimeManager ??= FindObjectOfType<IGPRuntimeManager>();
var initialized = await runtimeManager.InitializeAsync();
if (!initialized)
{
Debug.LogError("[IGP] SDK 初始化失败。");
return;
}
if (runtimeManager.IsDesktopSessionAttached)
{
Debug.Log("[IGP] Desktop session 已连接,可以使用正版校验、成就等桌面能力。");
}
}
}

关键点:

  • InitializeAsync() 是显式启动入口。只把 IGPRuntimeManager 放进场景不会自动启动 SDK。
  • IsDesktopSessionAttachedtrue 表示桌面能力链路已附着。
  • 房间链路需要额外等待 onRoomJoined;不要把“没有房间”误判为桌面能力失败。

正版校验在初始化过程中由 IGPRuntimeManager 处理。业务侧通常监听状态变化,并在失败时决定是否展示自定义 UI。

using UnityEngine;
using IGP.UnitySDK;
public sealed class IGPAuthorizationGate : MonoBehaviour
{
[SerializeField] private IGPRuntimeManager runtimeManager;
private void OnEnable()
{
runtimeManager.onAuthorizationStateChanged.AddListener(OnAuthorizationChanged);
runtimeManager.onAuthorizationFailed.AddListener(OnAuthorizationFailed);
}
private void OnDisable()
{
runtimeManager.onAuthorizationStateChanged.RemoveListener(OnAuthorizationChanged);
runtimeManager.onAuthorizationFailed.RemoveListener(OnAuthorizationFailed);
}
private void OnAuthorizationChanged(IGPAuthorizationState state)
{
if (runtimeManager.IsAuthorized)
{
// 允许进入主菜单或继续游戏。
}
}
private void OnAuthorizationFailed(string message)
{
Debug.LogError($"[IGP] 正版校验失败:{message}");
}
}
参数 / 字段含义
onAuthorizationStateChanged授权状态变化事件。常见成功状态是 AuthorizedOnlineAuthorizedOffline
onAuthorizationFailed授权失败事件,参数是失败说明。
IsAuthorized当前是否处于已授权状态。
IGPConfig.showAuthorizationFailureFallback是否显示 SDK 自带失败兜底提示。关闭后应由游戏自己展示失败 UI。

成就当前走 desktop session。调用前至少需要 InitializeAsync() 成功,并且 IsDesktopSessionAttached == true

using UnityEngine;
using IGP.UnitySDK;
using IGP.UnitySDK.Models;
public sealed class IGPAchievementDriver : MonoBehaviour
{
[SerializeField] private IGPRuntimeManager runtimeManager;
public async void UnlockFirstSession()
{
var result = await IGPSDK.UnlockAchievementAsync(
runtimeManager,
achievementKey: "first_session");
Debug.Log($"unlock success={result.success}, duplicated={result.duplicated}");
}
public async void AddMatchProgress()
{
var result = await IGPSDK.ReportAchievementProgressAsync(
runtimeManager,
achievementKey: "matches_played",
progressValue: 1,
progressSourceKey: "match_complete",
progressValueMode: ProgressValueMode.Increment);
Debug.Log($"progress success={result.success}, duplicated={result.duplicated}");
}
}
参数含义
achievementKey后台配置的成就 key,必须与平台配置一致。
progressValue进度值。具体含义由后台成就类型决定。
progressSourceKey进度来源标识,例如 match_completelevel_clear,用于排查和归因。
progressValueModeSet 表示设置为当前值,Increment 表示在当前进度上累加。
eventId幂等键。同一次业务事件重试时复用;不传时 SDK 会自动生成。
occurredAtUnixMs事件发生时间,Unix 毫秒;不传时由链路使用当前时间。
appId可选覆盖值。常规接入不传,SDK 使用 IGPConfig.appId

返回值:

字段含义
success是否处理成功。
duplicated是否命中幂等去重。重复解锁或重复上报不一定是错误。
message平台返回的说明文本。

房间、realtime、状态、RPC 和 KCP 都需要 hosted session。游戏通常由 IGP 桌面客户端按联调或正式流程启动,SDK 再通过启动信息进入房间。

using UnityEngine;
using IGP.UnitySDK;
using IGP.UnitySDK.Models;
public sealed class IGPRoomFlow : MonoBehaviour
{
[SerializeField] private IGPRuntimeManager runtimeManager;
private void OnEnable()
{
runtimeManager.onRoomJoined.AddListener(OnRoomJoined);
runtimeManager.onRoomUpdated.AddListener(OnRoomUpdated);
runtimeManager.onRoomLeft.AddListener(OnRoomLeft);
runtimeManager.onMapChanged.AddListener(OnMapChanged);
}
private void OnDisable()
{
runtimeManager.onRoomJoined.RemoveListener(OnRoomJoined);
runtimeManager.onRoomUpdated.RemoveListener(OnRoomUpdated);
runtimeManager.onRoomLeft.RemoveListener(OnRoomLeft);
runtimeManager.onMapChanged.RemoveListener(OnMapChanged);
}
private async void OnRoomJoined(Room room)
{
Debug.Log($"[IGP] joined room={room.id}, code={room.code}");
await runtimeManager.SetReadyAsync(true);
}
private void OnRoomUpdated(Room room)
{
// 刷新房间 UI、玩家列表、队伍状态等。
}
private void OnRoomLeft(Room room)
{
// 清理房间内状态。
}
private void OnMapChanged(IGPMapChangeData mapChange)
{
Debug.Log($"[IGP] map changed to {mapChange.currentMapPublicId}");
}
}
方法 / 事件含义
onRoomJoined(Room room)成功进入房间。常见做法是在这里初始化房间 UI 并调用 SetReadyAsync(true)
onRoomUpdated(Room room)房间快照更新。room.playersroom.globalStateroom.teams 等都以最新快照为准。
onRoomLeft(Room room)离开房间。用于清理 UI 和本地状态。
onMapChanged(IGPMapChangeData mapChange)同一房间内运行中换地图。使用 currentMapPublicId / currentMapVersionId 映射游戏自己的地图资源。
SetReadyAsync(bool isReady)设置当前玩家 ready 状态。
StartHostedGameAsync()请求开始游戏,通常由房主或具备权限的一端触发。
FinishHostedGameAsync()请求结束当前对局。
LeaveHostedRoomAsync()离开当前房间并断开 hosted 链路。

实时消息适合房间内自定义业务消息,例如聊天、表情、轻量玩法事件。发送前必须已经进入房间。

using System;
using UnityEngine;
using IGP.UnitySDK;
using IGP.UnitySDK.Models;
public sealed class IGPRealtimeDriver : MonoBehaviour
{
[SerializeField] private IGPRuntimeManager runtimeManager;
private void OnEnable()
{
runtimeManager.onMessageReceived.AddListener(OnMessageReceived);
}
private void OnDisable()
{
runtimeManager.onMessageReceived.RemoveListener(OnMessageReceived);
}
public async void SendChat(string text)
{
await runtimeManager.SendMessageAsync(new Message
{
type = "chat.message",
roomId = runtimeManager.CurrentRoomId,
playerId = runtimeManager.PlayerId,
reliable = true,
content = new
{
text,
sentAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
},
});
}
private void OnMessageReceived(string messageType, object content)
{
Debug.Log($"[IGP] message={messageType}, payload={content}");
}
}
Message 字段含义
type业务消息类型。不要使用 SDK 保留类型,例如 p2p_datastate_setrpc_call。建议使用稳定命名,如 chat.message
roomId当前房间 ID,通常填 runtimeManager.CurrentRoomId
playerId当前玩家 ID,通常填 runtimeManager.PlayerId
targetPlayerId可选目标玩家。为空通常表示房间广播。
content业务 payload。保持结构稳定,便于不同版本客户端兼容。
reliable是否使用可靠发送。当前房间实时消息建议保持 true

状态用于同步房间内共享数据或玩家数据;RPC 用于触发房间内命名逻辑。接收状态和 RPC 事件时,建议场景中同时放置 IGPEventManager

using System;
using UnityEngine;
using IGP.UnitySDK;
public sealed class IGPStateRpcDriver : MonoBehaviour
{
[SerializeField] private IGPRuntimeManager runtimeManager;
public async void SetScore()
{
await runtimeManager.SetGlobalStateAsync("match.score", new
{
red = 1,
blue = 0,
updatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
});
}
public async void SetLocalPlayerLoadout(string weaponId)
{
await runtimeManager.SetPlayerStateAsync("loadout.weapon", weaponId);
}
public async void RegisterEcho()
{
await runtimeManager.RegisterRPCAsync("sample.echo");
}
public async void CallEcho()
{
var requestId = await runtimeManager.CallRPCAsync(
"sample.echo",
new { text = "hello" },
mode: "all");
Debug.Log($"[IGP] rpc request={requestId}");
}
}
方法 / 参数含义
SetGlobalStateAsync(key, value)设置房间全局状态。适合比分、局内阶段等所有玩家共享的数据。
SetPlayerStateAsync(key, value)设置当前玩家状态。适合载入进度、角色选择、装备等玩家维度数据。
SetStateAsync(scope, key, value, targetPlayerId)通用状态入口。scope 常用 global / player
GetStateAsync(scope, key, targetPlayerId)请求读取指定状态。响应会通过状态消息 / 事件返回。
ResetStateAsync(scope, keysToExclude)重置指定作用域状态,可保留部分 key。
RegisterRPCAsync(name)注册当前客户端可处理的 RPC 名称。
CallRPCAsync(name, data, mode, requestId)调用 RPC。mode 常用 allrequestId 不传时 SDK 会生成请求 ID。
UnregisterRPCAsync(name)取消注册 RPC。

如果项目使用主包的低层数据面,入口在 runtimeManager.Network。这条链路需要已进入房间并完成 hosted data plane attach。

using System.Text;
using UnityEngine;
using IGP.UnitySDK;
using IGP.UnitySDK.Network;
public sealed class IGPP2PDriver : MonoBehaviour
{
[SerializeField] private IGPRuntimeManager runtimeManager;
private void OnEnable()
{
runtimeManager.Network.OnDataReceived.AddListener(OnDataReceived);
}
private void OnDisable()
{
runtimeManager.Network.OnDataReceived.RemoveListener(OnDataReceived);
}
public void BroadcastBytes()
{
var bytes = Encoding.UTF8.GetBytes("hello");
var result = runtimeManager.Network.SendReliableData(
new IGPPlayerID(runtimeManager.PlayerId),
new IGPPlayerID(""),
bytes,
(uint)bytes.Length,
message_type: 100);
Debug.Log($"[IGP] send result={result}");
}
private void OnDataReceived(IGPDataReceived data)
{
Debug.Log($"[IGP] p2p from={data.remote_peer}, type={data.message_type}, bytes={data.data.Length}");
}
}
参数含义
local_peer当前玩家 ID,通常是 runtimeManager.PlayerId
remote_peer目标玩家 ID;空字符串表示广播到房间。
data_buf / data_len要发送的字节数据和有效长度。
message_type业务自定义数字类型,用于接收端分发。
SendData适合较小 payload。超过当前数据面限制会返回 kErrorInvalidParam
SendReliableData允许 SDK 对较大 payload 自动分片,是大消息的优先入口。

多数运行时错误会通过两种方式暴露:

  • 抛出 IGPSDKException
  • 触发 runtimeManager.onError
try
{
await IGPSDK.UnlockAchievementAsync(runtimeManager, "first_session");
}
catch (IGPSDKException ex)
{
Debug.LogError(
$"[IGP] code={ex.ErrorCode}, category={ex.Category}, " +
$"channel={ex.DesktopChannelState}, attach={ex.DesktopAttachState}, message={ex.Message}");
}
字段含义
ErrorCodeSDK、desktop session 或 hosted 链路返回的错误码。
Category错误分类,例如 validationauthorizationchannelruntime
DesktopChannelStatedesktop session 通道状态快照,仅 desktop session 错误常见。
DesktopAttachStatedesktop attach 校验状态快照,仅 desktop session 错误常见。
Message可读错误说明。

排查建议:

  • 初始化失败时,先确认 appId 和本机 IGP 桌面客户端。
  • 桌面能力失败时,先看 IsDesktopSessionAttachedCurrentDesktopCapabilities 和授权状态。
  • 房间能力失败时,先看 onRoomJoined 是否触发,再看 IsHostedSessionAttachedCurrentHostedConnectionState
  • 数据面失败时,临时开启 debugLogging,观察 [IGP SDK] 日志。
  • 已导入 cn.indiegp.sdk.unity 主包。
  • 如需 Mirror 或实名认证与防沉迷,已导入对应可选包。
  • 场景里只有一个长期有效的 IGPRuntimeManager
  • IGPConfig.appId 已填写。
  • 游戏启动流程已调用 InitializeAsync()
  • 单机 / 非房间能力只验收 desktop session,不强等房间。
  • 房间、realtime、state、RPC、KCP 能力只在进入房间后调用。
  • 成就 key、状态 key、RPC 名称、消息 type 都使用稳定命名,并与后台配置或业务协议一致。
  • 幂等参数 eventId / requestId 在同一次业务重试时复用,新业务事件重新生成。
  • 正式发布前关闭 debugLogging,并按 联调与测试 完成检查。