大约是2023年2月底,Epic开放了开发者自由发布游戏的权限,和Steam一样需要缴纳100刀即可发布游戏,并且开发引擎没有限制,你用Unity开发的游戏也可以发布(UE开发会有减免)。我也将之前旧的项目发布上去试试,没想到流程如此繁琐,历时了N个下班后的夜晚终于将发布流程走通。
如果你也在接入可以通过这篇文章进行参考,有任何不明白的地方可以直接indienova私信我。
1.如何开始
在Epic商店底部点击按钮即可进入Epic开发者相关操作页面。
通常会有一系列注册流程,在这之后需要创建组织并创建产品,大致如下:
1.1 税务审查
新账户会提示填写税务审查资料,网上一些朋友被提示因地址填写问题审核失败,我也因地址填写问题被打回一次,后来按照英文格式详细填写了一遍就审核通过了。
2.发布管理
接下来就可以进行商店页的编辑操作,Epic后台与Steam不同,它分为3个部分,所有的编辑操作都在Dev部分进行,随后推送到Stage后可提交审核,审核完毕可随时推送至Live。
页面编辑部分没有较多难点,此处略过。
2.1 日期设置
如果需要开卖而不是攒愿望单,需要检查"商品"-"发行日期",改为特定,否则你的游戏只能看到页面,无法进入售卖环节审核(坑啊)。
3.程序包提交
3.1 BuildPatch Tool
Epic游戏包提交通过BuildPatch Tool工具,可在后台面板此处进行下载。
该工具与Steam程序包提交方式类似,但需要手动编写批处理文件并指定各种Id。例如我们可以在这个目录进行一些文件创建:
打开压缩包附带的pdf文档,有如何提交这些参数的说明:
bat文件可编写如下:
BuildPatchTool.exe -OrganizationId="" -ProductId="" -ArtifactId="" -ClientId="" -ClientSecret="" -mode=UploadBinary -BuildRoot="./Release_Epic" -BuildVersion="1001" -AppLaunch="yourApp.exe" -AppArgs="" -FileAttributeList="" -FileIgnoreList=""
最后将程序包和bat都编辑好后,大致如下:
下面将讲讲这些Id如何获取。
3.2 BuildPatch Tool的各类Id
ProductId可在产品设置(SDK下载与凭证)中找到:
OrganizationId在"组织"->"设置"这里:
ArtifactId在"构建与二进制文件":
最后的ClientId和密钥在BPT(不在SDK下载与凭证那一栏,很坑):
3.3 提交应用
运行bat没有问题后就会提交到后台,然后需要在后台”构建与二进制文件“,创建对应构建,点击”分配平台“,设置新的版本id即可生效:
3.4 商品设置
还需要在"商品详情"->"构建设置"处配置构建对应的文件夹。
最后这部分可能还有一些疏漏内容,因为是已经提交完成的状态没法复现,请大家自行查询文档完成剩余步骤。
4.杂项
4.1 账户服务
然后还需要开通账户服务,点击右侧"创建应用程序"即可。
创建后"许可"和"已关联客户端"部分很简单,但"品牌设置"这一项比较麻烦,需要创建官方网站,但看网上一些朋友的流程,好像不设置也不影响游戏上架。
但这一步我是完成了操作的,创建工作室官网并绑定品牌设置的流程:
1.在域名的txt地址解析处粘贴上epic的一串验证码,验证域名。域名用非.com后缀也可,所以购买那种1块钱的域名就可以解决。
2.主机不管后台是什么样的,需要支持https(对,仔细看会发现要https开头的网站),并且需要一个主页网页和一个PrivacyPolic隐私政策网页,隐私政策随便找一个别的产品作为模板改下就行。
我配置好后的页面长这样:
4.2 产品设置-客户端策略
接下来设置客户端策略,以便为玩家开通成就权限等
Metrics必须勾选,否则无法统计后台数据。unlockAchievementForLocalUser必须勾选,否则影响到成就接入(添加新的策略时选择特殊策略模板即可勾选)。
5.成就接入
5.1 创建成就
如果你的游戏在steam上(或别的平台)有成就,你就必须在Epic上也接入成就,否则审核不让你通过。接下来讲讲操作。
在"游戏服务"->"成就"处可以查看成就,点击创建成就这时会提示"添加统计信息",无需勾选。
下一步,成就id就是你在unity里需要填入解锁的id,和steam一样:
5.2 分配成就奖励
和steam不一样,epic创建的成就要分配满1000经验值的奖励。
5.3 成就测试
那么测试游戏的时候怎么知道自己已经获得了成就呢?在Epic库中,可以将预览模式设置为Dev以进行查看
5.4 推送
最后留意2件事情,成就在Live面板是否存在,是否点击推送到台面。我记得推送到台面按钮是要经过审核才会出现。
6.Unity SDK接入
6.1 安装Unity版本SDK
终于来到Unity SDK接入的部分,官网封装的很烂,我使用的是网络上开源的Unity封装版本:
https://github.com/PlayEveryWare/eos_plugin_for_unity_upm
注意:一定要用导入git包的功能导入到Unity Package Manager,不行自己挂一个梯子。
我就是第一次直接下载的包,导致文件不一致报错了。
6.2 配置
在入口场景新建一个GameObject挂载EOSManager和登录:
登录脚本EpicLogin出处:https://blog.csdn.net/final5788/article/details/128202742
脚本内容如下:
public class EpicLogin : MonoBehaviour { private ProductUserId _productUserId; private void Start() { DontDestroyOnLoad(gameObject); Login(); } public void Login() { var token = string.Empty; string[] commandArgs = Environment.GetCommandLineArgs(); foreach (var commandArg in commandArgs) { if (commandArg.Contains("AUTH_PASSWORD")) { var args = commandArg.Split('='); if (args.Length >= 2) { token = args[1]; } } } EOSManager.Instance.StartLoginWithLoginTypeAndToken(LoginCredentialType.AccountPortal, null, token, callbackInfo => { if (callbackInfo.ResultCode != Epic.OnlineServices.Result.Success) { LoginWithPersistentMode(); } else { StartLoginWithLoginTypeAndTokenCallback(callbackInfo); } }); } public void LoginWithPersistentMode() { EOSManager.Instance.StartPersistentLogin((Epic.OnlineServices.Auth.LoginCallbackInfo callbackInfo) => { if (callbackInfo.ResultCode != Epic.OnlineServices.Result.Success) { LoginWithLoginTypeAndToken(); } else { StartLoginWithLoginTypeAndTokenCallback(callbackInfo); } }); } private void LoginWithLoginTypeAndToken() { EOSManager.Instance.StartLoginWithLoginTypeAndToken( Epic.OnlineServices.Auth.LoginCredentialType.AccountPortal, ExternalCredentialType.Epic, null, null, loginResult => { EOSManager.Instance.StartConnectLoginWithEpicAccount(loginResult.LocalUserId, (Epic.OnlineServices.Connect.LoginCallbackInfo connectLoginCallbackInfo) => { if (connectLoginCallbackInfo.ResultCode == Result.Success) { _productUserId = connectLoginCallbackInfo.LocalUserId; } else if (connectLoginCallbackInfo.ResultCode == Result.InvalidUser) { // ask user if they want to connect; sample assumes they do EOSManager.Instance.CreateConnectUserWithContinuanceToken(connectLoginCallbackInfo.ContinuanceToken, (Epic.OnlineServices.Connect.CreateUserCallbackInfo createUserCallbackInfo) => { EOSManager.Instance.StartConnectLoginWithEpicAccount(loginResult.LocalUserId, (Epic.OnlineServices.Connect.LoginCallbackInfo retryConnectLoginCallbackInfo) => { if (retryConnectLoginCallbackInfo.ResultCode == Result.Success) { _productUserId = retryConnectLoginCallbackInfo.LocalUserId; } }); }); } else { } }); }); } private void StartConnectLoginWithLoginCallbackInfo(LoginCallbackInfo loginCallbackInfo) { EOSManager.Instance.StartConnectLoginWithEpicAccount(loginCallbackInfo.LocalUserId, (Epic.OnlineServices.Connect.LoginCallbackInfo connectLoginCallbackInfo) => { if (connectLoginCallbackInfo.ResultCode == Result.Success) { _productUserId = connectLoginCallbackInfo.LocalUserId; } else if (connectLoginCallbackInfo.ResultCode == Result.InvalidUser) { EOSManager.Instance.CreateConnectUserWithContinuanceToken(connectLoginCallbackInfo.ContinuanceToken, (Epic.OnlineServices.Connect.CreateUserCallbackInfo createUserCallbackInfo) => { EOSManager.Instance.StartConnectLoginWithEpicAccount(loginCallbackInfo.LocalUserId, (Epic.OnlineServices.Connect.LoginCallbackInfo retryConnectLoginCallbackInfo) => { if (retryConnectLoginCallbackInfo.ResultCode == Result.Success) { _productUserId = retryConnectLoginCallbackInfo.LocalUserId; } }); }); } }); } public void StartLoginWithLoginTypeAndTokenCallback(LoginCallbackInfo loginCallbackInfo) { if (loginCallbackInfo.ResultCode == Epic.OnlineServices.Result.AuthMFARequired) { // collect MFA // do something to give the MFA to the SDK print("MFA Authentication not supported in sample. [" + loginCallbackInfo.ResultCode + "]"); } else if (loginCallbackInfo.ResultCode == Result.AuthPinGrantCode) { ///TODO(mendsley): Handle pin-grant in a more reasonable way } else if (loginCallbackInfo.ResultCode == Epic.OnlineServices.Result.Success) { StartConnectLoginWithLoginCallbackInfo(loginCallbackInfo); } else if (loginCallbackInfo.ResultCode == Epic.OnlineServices.Result.InvalidUser) { EOSManager.Instance.AuthLinkExternalAccountWithContinuanceToken(loginCallbackInfo.ContinuanceToken, #if UNITY_SWITCH LinkAccountFlags.NintendoNsaId, #else LinkAccountFlags.NoFlags, #endif (Epic.OnlineServices.Auth.LinkAccountCallbackInfo linkAccountCallbackInfo) => { if (linkAccountCallbackInfo.ResultCode == Result.Success) { StartConnectLoginWithLoginCallbackInfo(loginCallbackInfo); } else { print("Error Doing AuthLink with continuance token in. [" + linkAccountCallbackInfo.ResultCode + "]"); } }); } else { print("Error logging in. [" + loginCallbackInfo.ResultCode + "]"); } // Re-enable the login button and associated UI on any error if (loginCallbackInfo.ResultCode != Epic.OnlineServices.Result.Success) { //ConfigureUIForLogin(); } } }
在Unity顶部菜单的Tools->EosPlugin->Dev Portal Configuration处配置各类Id,蓝色框出的区域可以不用配置,所有的配置内容都在SDK下载与凭证那一栏,ClietID也用这一栏的。
出包之后检查有没有EOSBootstrapper文件,如果没有就说明SDK没装正确:
6.3 成就Unity部分
导入SDK插件的第一个案例,案例中封装好了成就管理器,会稍微方便些。
成就代码:
public static class EpicAchievementMediator { public static void CompleteAchievement(string achievementID) { UnlockAchievementsOptions options = new UnlockAchievementsOptions(); options.AchievementIds = new Epic.OnlineServices.Utf8String[1]; options.AchievementIds[0] = new Epic.OnlineServices.Utf8String(achievementID); EOSManager.Instance.GetEOSAchievementInterface().UnlockAchievements(ref options, null, null); EOSManager.Instance.GetOrCreateManager<EOSAchievementManager>().RefreshData(); try { EOSManager.Instance.GetOrCreateManager<EOSAchievementManager>().UnlockAchievementManually(achievementID, (ref OnUnlockAchievementsCompleteCallbackInfo info) => { if (info.ResultCode == Result.Success) { Debug.LogError("UnlockAchievement Succeesful"); EOSManager.Instance.GetOrCreateManager<EOSAchievementManager>().RefreshData(); } Debug.LogError("info.ResultCode: " + info.ResultCode); }); } catch (System.Exception e) { Debug.LogError("Errr! " + e); } } }
6.4 打包测试
最后打包、上传、后台更新最新包体Id,进入Epic启动器测试,如果游戏运行时有Epic Overlay UI覆盖在游戏之上,并且获得成就也会有Epic UI的成就特效,基本上说明成功了,可以丢给Epic审核。
最近正在头疼epic的sdk的事,终于看到一个靠谱的文章!
您好请教一下,您的这个BuildRoot="./Release_Epic"是本体包么(是Steam版本得Shipping包?),然后CloudDir这个参数是填写存放这个zip包得吗,感谢大佬,卡了很久
@ELIAUK:是本体包放置的文件夹,肯定是要移除掉Steam SDK相关内容,CloudDir这个参数我测试过,不填写也可以上传到后台。
@hont:谢谢大佬~
感谢分享
上传mac 二进制 参数该如何填写呢? 有点蒙蔽
@妄: 搞定了
set OrganizationId="xxxxxxxxxxxxxx"
set ProductId="xxxxxxxxxxxxxx"
set ArtifactId="xxxxxxxxxxxxxx"
set ClientId="xxxxxxxxxxxxxx"
set ClientSecret="xxxxxxxxxxxxxxE"
set BuildRoot="./content_mac"
set CloudDir="./DLC"
set BuildVersion="1.0"
set AppLaunch="Epic_Mac.app/Contents/MacOS/名字"
set AppArgs=""
BuildPatchTool.exe -OrganizationId=%OrganizationId% -ProductId=%ProductId% -ArtifactId=%ArtifactId% -ClientId=%ClientId% -ClientSecret=%ClientSecret% -mode=UploadBinary -BuildRoot=%BuildRoot% -CloudDir=%CloudDir% -BuildVersion=%BuildVersion% -AppLaunch=%AppLaunch% -AppArgs=%AppArgs%