大约是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%
大佬请问下 我上传到dev 沙盒 和 stage 沙盒后 怎么测试通过交换代码实现自动登录呀 还有dlc功能 感觉这些都要审核上线到商城后才能测试的
最近由 Ame林汀 修改于:2024-12-17 10:39:58@Ame林汀:已经解决