# PC SDK Unity对接指南

# 介绍

独立游戏的STOVE平台提供包括游戏发行及销售、社区、指标分析等在内的游戏上市所有过程一站式处理综合服务。 使用PC SDK(Unity,以下简称PC SDK)可以轻松将Stove平台提供的服务整合到游戏中。

这里说明连接PC SDK的方法。

confirm 如果是第一次对接PC SDK,请先阅读PC SDK Unity示例

# 事前准备

  • 确认是否在STOVE Studio (opens new window)上获得了加入STOVE的账户和游戏上线用Appkey、App secret、Game Id。
  • 建议设置Unity 2017以上和Visual Studio 2017以上版本。
  • PC SDK 下载页面上下载最新版本的Unity(C#)分发文件(以下标记为StovePCSDK_NET)。

# StovePCSDK_NET发行文件配置

# 1) StovePCSDK 文件夹

下载并解压缩STovePCSDK_NET,StovePCSDK文件夹包含以下文件夹。

    • Plugins
      Unity Project插件文件夹。
    • Plugins\x86
      包含x86平台所需的二进制文件。
    • Plugins\x86_64
      x64平台所需的二进制文件。

# StovePCSDK_NET 构建环境

# 1) 添加 Assets

打开要合并的Unity项目,保留上述StovePCSDK 文件夹内x86x86_64文件夹中的一个,并删除另一文件夹,然后复制 "StovePCSDK` 文件夹并将其粘贴到Assets文件夹的下游。

Figure1
Figure2

# 2) 检查x86文件夹中的文件

选择x86文件夹下方的文件,并检查Inspector的Platform settings部分是否勾选了 Windows x86条目。如果未选中,请选择复选框。

Figure3
Figure4

# 3) 检查x86_64文件夹中的文件

选择x86_64文件夹下方的文件,并检查Inspector的Platform settings部分是否勾选了Windows x86_x64条目。如果未选中,请选择复选框。

Figure5
Figure6

# #### 4) Build Settings

单击File > Build Settings...菜单,打开 Build Settings对话框,点击Player Settings...按钮,打开Inspector或Project Settings窗口。 Other Settings组 > Configuration领域 > Api Compatibility Level项目设置如下:
Unity 2018以前版本:.NET 2.0(不是.NET 2.0 Subset)

Figure11

Unity 2018以后版本:.NET 4.x(不是.NET Standard 2.0)

Figure12

# 5) 创建空游戏目标

在适当的场景中创建GameObject -> Create Empty。为了方便起见,名称设置为 StovePCSDKManager。

Figure7
Figure8

# 6) 添加脚本组件

将Script组件添加到StovePCSDKManager Object。 为了方便起见,脚本的名称设置为StovePCSDKManager

Figure9
Figure10

# 7) 创建脚本

在Awake方法中执行以下处理,以便StovePCSDKManager Object不会因场景切换等因素解除。

private void Awake()
{
    DontDestroyOnLoad(transform.gameObject);
}
1
2
3
4

# 对接PC SDK

# 1) RunCallback

PC SDK的API为了不妨碍游戏引擎及游戏逻辑,大部分都是异步执行。 API呼叫的结果将装载在PC SDK内部的队列上,游戏想要处理API呼叫的结果时,通过呼叫RunCallback方法进行相应回拨。 一般情况下RunCallback方法的呼叫使用Corutin编写,呼叫周期可以设置。

private IEnumerator RunCallback(float intervalSeconds)
{
    WaitForSeconds wfs = new WaitForSeconds(intervalSeconds);
    while (true)
    {
        StovePC.RunCallback();
        yield return wfs;
    }
}
1
2
3
4
5
6
7
8
9

Corutin通过MonoBehaviour.StartCoroutine方法开始,一般是PC SDK初始化 成功后启动,PCSDK退出成功后停止。 PC SDK退出成功后,为了终止RunCallback Corutin,可使用成员变量方法。

private Coroutine runcallbackCoroutine;
1

游戏项目中的成员变量 runcallback Coroutine,可如下面的代码所示,使用StartCoroutine 函数和StopCoroutine 函数,使它们像定时器一样工作。

public void ToggleRunCallback_ValueChanged(bool isOn)
    {
        if (isOn)
        {
            float intervalSeconds = 1f;
            runcallbackCoroutine = StartCoroutine(RunCallback(intervalSeconds));

            WriteLog("RunCallback Start");
        }
        else
        {
            if (runcallbackCoroutine != null)
            {
                StopCoroutine(runcallbackCoroutine);
                runcallbackCoroutine = null;

                WriteLog("RunCallback Stop");
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2) Config, Callback配置

为了初始化PC SDK,首先为填写StovePCConfigStovePCCallback结构体,然后调用 StovePC.Initialize方法。 参考以下代码填充StovePCConfig结构体的每个字段值。

StovePCConfig config = new StovePCConfig
{
    Env = "live",
    AppKey = "YOUR_APP_KEY",
    AppSecret = "YOUR_SECRET_KEY",
    GameId = "YOUR_GAME_ID",
    LogLevel = StovePCLogLevel.Debug,
    LogPath = ""
};
1
2
3
4
5
6
7
8
9

confirm "YOUR_APP_KEY", "YOUR_SECRET_KEY", "YOUR_GAME_ID"必须填写STOVE Studio发放的密钥值。 未登录STOVE客户端调用stovePC.Initialize方法时会报错,请提前运行STOVE客户端并登录。

游戏和PC SDK之间的对接使用C# Delegate。 游戏需要定义以下StovePCCallback Class回拨相关的Deligate方法:

public class StovePCCallback
{
    // StovePCSDK 发生错误时调用回拨
    public StovePCErrorDelegate OnError;

    // PC SDK 初始化完成后呼叫的回拨
    public StovePCInitializationCompleteDelegate OnInitializationComplete;

    // GetToken 处理完成时调用回拨
    public StovePCTokenDelegate OnToken;

    // GetUser 处理完成时调用回拨
    public StovePCUserDelegate OnUser;

    // GetOwnership 处理完成时调用回拨
    public StovePCOwnershipDelegate OnOwnership;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

此处需要注意的是,StovePCCallback客体应保存到PCSDK结束为止。其理由是StovePCCallback客体一旦进行Gavage collecting,PC SDK内部就无法呼叫回拨。 为了满足这一点,StovePCCallback class 可以被宣布为游戏项目class的成员变量,从而避免Gavage收集。

private StovePCCallback callback;
1
// 创建 StovePCCallback 类 instance 
this.callback = new StovePCCallback
{
    OnError = new StovePCErrorDelegate(this.OnError),
    OnInitializationComplete = new StovePCInitializationCompleteDelegate(this.OnInitializationComplete),
    OnToken = new StovePCTokenDelegate(this.OnToken),
    OnUser = new StovePCUserDelegate(this.OnUser),
    OnOwnership = new StovePCOwnershipDelegate(this.OnOwnership)
};
1
2
3
4
5
6
7
8
9

除必须对接的"OnError"、"OnInitialization Complete"、"OnOwnership"回调函数,其余回调函数可在必要时进行对接。例如,仅使用所有权(Ownership)功能时,可使用如下连接Deligate方法。

/*
仅使用所有权(Ownership)功能时,
除了必须实现的回拨OnError、OnInitialization Complete之外
对接OnOwnership呼叫。
*/
this.callback = new StovePCCallback
{
    OnError = new StovePCErrorDelegate(this.OnError),
    OnInitializationComplete = new StovePCInitializationCompleteDelegate(this.OnInitializationComplete),
    OnOwnership = new StovePCOwnershipDelegate(this.OnOwnership)
};
1
2
3
4
5
6
7
8
9
10
11

# 3) SDK 初始化

调用StovePC.Initialize方法来初始化PC SDK。

StovePCResult sdkResult = StovePC.Initialize(config, this.callback);
if (StovePCResult.NoError == sdkResult)
{
    this.runCallbackCoroutine = StartCoroutine(RunCallback(0.5f));
    // 没有初始化错误,故循环调用RunCallback 
}
else
{
    // 初始化失败,终止游戏
}
1
2
3
4
5
6
7
8
9
10

StovePC.Initialize方法在确认config和callback有效性后,立即返回StovePCResult enum 类型值。 如果成功,则返回StovePCResult.NoError值。失败时,应返还相应错误代码,并终止游戏。

返回值为StovePCResult.NoError,即成功时,定期调用StovePC. RunCallback 方法。 只有定期调用StovePC. RunCallback 方法,连接的回拨才会正常调用。 如果呼叫周期长,回拨的响应速度也会变慢,因此最好保持适当的呼叫周期。示例代码中设定为每秒调用一次回传函数。

confirm 用Initialize方法初始化PC SDK的线程(Thread) 和`StovePC.RunCallback' 方法调用返回函数的线程必须相同。

"StovePC.Initialize方法除确认config和callback有效性外,其它操作均以异步处理。 异步操作成功时,调用OnInitialization Complete回拨;发生错误时,调用OnError回拨。 发生错误时,可通过传送的StovePCError`结构体确认错误代码、信息等。

private void OnInitializationComplete()
{
    Debug.Log("PC SDK initialization success");
}

    private void OnError(StovePCError error)
    {
        #region Log
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("OnError");
        sb.AppendFormat(" - error.FunctionType : {0}" + Environment.NewLine, error.FunctionType.ToString());
        sb.AppendFormat(" - error.Result : {0}" + Environment.NewLine, (int)error.Result);
        sb.AppendFormat(" - error.Message : {0}" + Environment.NewLine, error.Message);
        sb.AppendFormat(" - error.ExternalError : {0}", error.ExternalError.ToString());
        WriteLog(sb.ToString());
        #endregion

        switch (error.FunctionType)
        {
            case StovePCFunctionType.Initialize:
            case StovePCFunctionType.GetUser:
            case StovePCFunctionType.GetOwnership:
                BeginQuitAppDueToError();
                break;
        }
    }

    private void BeginQuitAppDueToError()
    {
        #region Log
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("BeginQuitAppDueToError");
        sb.AppendFormat(" - nothing");
        WriteLog(sb.ToString());
        #endregion

        // 或许,与其说您立即中断应用程序,不如向用户展示关于中断应用程序的信息后,
        // 根据用户动作(e.g.点击结束按钮)可能想要中断应用程序。
        // 那么,请在此删除 QuitApplication ,以实现您的专属逻辑。
        // 关于建议的必要事前作业错误的信息如下。
        // 韩语:필수 사전 작업이 실패하여 게임을 종료합니다.
        // 其它语言 : The required pre-task fails and exits the game.
        QuitApplication();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

如果需要在 OnInitialisationComplete 回调之前查找 PC SDK 的初始化状态值,可以使用 StovePC.GetInitialisationState 函数。

// 调用 StovePC.Initialize 之后...
while (StovePC.GetInitializationState() == StovePCInitializationState.Pending)
{
    Thread.Sleep(500);
    StovePC.RunCallback();
}

if (StovePC.GetInitializationState() == StovePCInitializationState.Complete)
{
    // 초기화 완료 OnInitializationComplete 콜백이 호출됨
}
else
{
    // 초기화 실패 OnError 콜백이 호출됨
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

如果需要在 OnInitialisationComplete 回调之前查找 PC SDK 的初始化状态值,可以使用 StovePC.GetInitialisationState 函数。

// 调用 StovePC.Initialize 之后...
while (StovePC.GetInitializationState() == StovePCInitializationState.Pending)
{
    Thread.Sleep(500);
    StovePC.RunCallback();
}

if (StovePC.GetInitializationState() == StovePCInitializationState.Complete)
{
    // 初始化完成 OnInitialisationComplete 回调被调用
}
else
{
    // 初始化完成 OnInitialisationComplete 回调被调用
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 4) 对接SDK时的注意事项

confirm 在初始化完成之前调用GetToken,GetUser,GetOwnership 方法可能无法正常获得结果。也就是说,在正常接收到OnInitialization Complete回拨后,必须调用"GetToken"、"GetUser"、"GetOwnership"方法才能正常收到结果。

confirm StovePCCConfig 结构体设置日志级别时,PC SDK测试时请输入StovePCLogLevel.Debug值,正式构建时请设置StovePCLogLevel.Eror值,防止产生不必要的日志。

# 5) SDK 退出

结束PC SDK使用后通过呼叫整理使用中的资源。调用StovePC.Uninitialize方法后,PC SDK 的API将停止工作。在调用StovePC.Uninitialize方法之前或之后,必须通过StopCoroutine函数停止runcallbackCoroutine的Coroutine运行。

StovePCResult result = StovePC.Uninitialize();
if (result == StovePCResult.NoError)
{
    // 成功处理
}
1
2
3
4
5

# 6) 获取用户信息

您可以使用StovePC.GetUser方法查看登录到STOVE客户端 (opens new window)的用户信息。

StovePCResult result = StovePC.GetUser();
if (result == StovePCResult.NoError)
{
    // 成功处理
}
1
2
3
4
5

正常处理StovePC.GetUser方法后,调用OnUser回拨。 通过Callback上传达的StovePCUser结构体,可以了解用户的成员号码、昵称、游戏用户ID信息。

private void OnUser(StovePCUser user)
{
    // 输出用户信息
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("OnUser");    
    sb.AppendFormat(" - user.MemberNo : {0}" + Environment.NewLine, user.MemberNo.ToString());
    sb.AppendFormat(" - user.Nickname : {0}" + Environment.NewLine, user.Nickname);
    sb.AppendFormat(" - user.GameUserId : {0}", user.GameUserId);
    
    Debug.Log(sb.ToString());
}
1
2
3
4
5
6
7
8
9
10
11

# 7) 获取令牌信息

获取使用StovePC.GetToken方法登录到STOVE客户端的用户的令牌信息。

StovePCResult result = StovePC.GetToken();
if (result == StovePCResult.NoError)
{
    // 成功处理
}
1
2
3
4
5

如果正常处理了StovePC.GetToken方法,则调用OnToken回拨 传递到回拨的StovePCToken 结构包含令牌字符串。

private void OnToken(StovePCToken token)
{
    // 令牌信息输出
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("OnToken");
    sb.AppendFormat(" - token.AccessToken : {0}", token.AccessToken);

    Debug.Log(sb.ToString());
}
1
2
3
4
5
6
7
8
9

confirm 令牌是什么? 通过登录STOVE Launcher的用户的Access Token,游戏服务器可以将该Access Token传达给Stove认证服务器,进行登录用户的有效性验证。 有关Access Token的详细说明,请咨询store.support@smilegate.com获得技术支援。

# 8) 获取所有权信息

使用StovePC.GetOwnership 方法查询登录STOVE客户端的用户是否购买并拥有该游戏。

StovePCResult result = StovePC.GetOwnership();
if (result == StovePCResult.NoError)
{
    // 成功处理
}
1
2
3
4
5

如果正常处理了StovePC.GetOwnership方法,则调用OnOwnership回拨。 下面是OnOwnership回拨中判断是否购买游戏的示例代码。 没有DLC的游戏时,不需要22~27行的确认代码。

private void OnOwnership(StovePCOwnership[] ownerships)
{
    bool owned = false;
 
    foreach(var ownership in ownerships)
    {
        // [LOGIN_USER_MEMBER_NO] StovePCUser 构造体的 MemberNo
        // [Ownership Code] 1:取得所有权,2:所有权解除(取消购买时)
        if (ownership.MemberNo != LOGIN_USER_MEMBER_NO ||
            ownership.OwnershipCode != 1)
        {
            continue;
        }
 
        // [GameCode] 3: BASIC 游戏, 4: DEMO
        if (ownership.GameId == "YOUR_GAME_ID" &&
            ownership.GameCode == 3)
        {
            设置为 owned = true; // 所有权确认变量设为true
        }
 
        // 只有销售DLC的游戏时才需要
        if (ownership.GameId == "YOUR_DLC_ID" &&
            ownership.GameCode == 5)
        {
            // 因为拥有YOUR_DLC_ID(DLC)所有权,所以允许使用DLC
        }
    }
     
    if(owned)
    {
        // 所有权验证正常完成后创建进入游戏的logic
    }
    else
    {
        // 所有权验证失败后终止游戏,进行错误信息显示逻辑
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  • 用购买游戏的账户(拥有所有权)登录STOVE客户端后即可正常游戏。
  • 用没有游戏所有权的账号登录STOVE客户端后,运行exe时显示以下提示信息(示例)后终止游戏。
    • 韩语以外的操作系统 : Please log in to STOVE Client with the account that has purchased the game.
    • 韩语:게임을 구매한 계정으로 STOVE 클라이언트에 로그인하시기 바랍니다.

confirm 即使没有拥有游戏所有权的账号,也可以测试所有权功能,详细方法请确认FAQ

  • 另外,调用所有权( Ownership) <GetOwnership Success> 后,请在 output_log.txt 或 Player.log 中添加以下日志:
示例 :

成功: 拥有所有权的用户。
失败: 没有所有权的用户。
1
2
3
4
  • 日志文件激活指南: [https://docs.unity3d.com/530/Documentation/Manual/LogFiles.html] (https://docs.unity3d.com/530/Documentation/Manual/LogFiles.html)

# 确认错误

PC SDK使用过程中发生的错误大致可分为两种情况。

# 调用方法后返回的 StovePCResultenum 值

PC SDK 的全部方法将在调用后立即返回StovePCResult enum 值,表示调用是否成功。 返回的错误代码可在PCSDK 错误代码 页面上查看。

# 通过 OnError 回拨传递的 StovePCError 结构

PC SDK API 发生错误时,将会调用OnError 回拨,传递包含错误详细信息的StovePCError 结构体。

// OnError 回拨将在调用时传递。
public struct StovePCError
{
    // 显示调用函数的 enum 值
    public StovePCFunctionType FunctionType;

    // 显示错误类型的 enum 值
    public StovePCResult Result;

    // 发生错误消息
    public string Message;

    // 外部错误(http 错误,外部模块错误)发生时,相应的错误代码
    public int ExternalError;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Last Updated: 2024/3/4 13:52:06