典型用例场景
案例1:使用虚拟服务器的游戏活动
1.1 活动描述
活动名称:新武器试玩活动 活动简介:我们为游戏设计了一款新武器。我们希望收集玩家对该武器的反馈。反馈将以游戏内投票的形式进行。 活动规则:
- 玩家在晚上 20:00 至 20:59 之间登录游戏,即可获得该新武器试玩,并通过游戏内提示进行通知。
- 我们会记录每位玩家使用该武器的游玩次数。玩家每参与一场战斗并使用该武器进行战斗,游玩次数就会加 1。
- 游玩次数达到 5 次后,将弹出投票框,让玩家提交试玩分数,分数范围为 0 至 5。
- 活动将持续一周,之后我们将计算该武器的最终分数。
1.2 技术设计
- 新武器授予:创建一个虚拟服务器来处理授予。该服务器需要配置为与 Portal 上的 PGOS 事件
event_player_login_pgos
绑定。当玩家登录时,该虚拟服务器将被触发,并通过游戏内提示消息通知玩家新武器已授予。
游戏次数处理:在玩家数据模板页面中定义一个名为“NewWeaponPlayCount”的新键,默认值为0。每当玩家使用该武器加入战斗时,专属服务器都会更新该键。
投票:如果玩家的“NewWeaponPlayCount”字段等于5,虚拟服务器将通知游戏客户端使用PushMsg API向该玩家弹出投票消息框。玩家发布投票结果后,游戏客户端将访问虚拟服务器记录投票结果。
投票结果记录:我们将投票结果记录在“title region config data”中,分别作为“TotalScore”和“TotalPlayers”字段。新武器的最终得分将等于“TotalVoteScore”/“TotalVotePlayers”的值。
sequenceDiagram Game Client ->>+ Game Dedicated Server: Join Battle Game Dedicated Server ->>- Virtual Server: Update Play Count (End of Battle) Virtual Server ->> Player Data: Set NewWeaponPlayCount+=1 Virtual Server ->> Game Client: Notify Vote (if NewWeaponPlayCount==5) Game Client ->> Game Client: Prompt Vote UI Game Client ->> Virtual Server: Post Vote Result Virtual Server ->> TitleData: Update TotalVoteScore & TotalVotePlayers
1.3 键值源代码
- 玩家数据和标题区域配置数据字段定义
在“Players/Data Template”页面中,我们添加了一个名为“NewWeaponPlayCount”的key,默认值为0,并赋予“Internal”权限。
在“Title Region/Config Data”页面中,我们添加了名为“TotalVoteScore”和“TotalVotePlayers”的key,默认值均为0。
- 虚拟服务器
创建一个名为“CampaignServer”的虚拟服务器,其关键源代码如下:
授予武器:
// grant weapon when player login, triggered by event_player_login_pgos
exports.login_grant = async (args, context) => {
// check if in desired time range
var dt = new Date(context.event.data.start_time)
var h = dt.getHours()
if ( h != 20) {
return "no granting"
}
// grant weapon to player
grant_res = await server.GrantItemsToPlayer(req)
if (grant_res.result != 0) {
return "granting failed"
}
let msg = {
name: "new_weapon_grant",
item_instance_id: grant_res.body.item_instances[0].instance_id
}
// notify game client
let pushMsgData = {
player_id_list: [context.event.data.player_id],
msg: JSON.stringify(msg)
}
return await server.PushMsg(pushMsg)
}
更新玩家数:
// update NewWeaponPlayCount and notify player to vote, accessed by game dedicated server
exports.update_play_count = async (args, context) => {
if (args.player_id === "") {
return "failed"
}
let reqData = {
"player_items": [
{
"items": [
{
"key": "NewWeaponPlayCount",
"incr": 1
}
],
"player_id": args.player_id
}
]
}
let notifyVote = false
let res = await server.IncrPlayerKVDataInt(reqData);
if (res.result == 0) {
if (res.body.data.data_list.length > 0) {
if (res.body.data.data_list[0].key == "NewWeaponPlayCount") {
if (parseInt(res.body.data.data_list[0].value) == 5) {
notifyVote = true
}
}
}
}
if (notifyVote) {
// notify game client to vote
let msg = {
name: "new_weapon_vote"
}
let pushMsgData = {
player_id_list: [context.event.data.player_id],
msg: JSON.stringify(msg)
}
return await server.PushMsg(pushMsgData)
}
}
发表投票:
// post vote, accessed by game client
exports.post_vote = async (args, context) => {
if (args.player_id === "" || args.score === "") {
return "failed"
}
let reqData = {
"data": [
{
"key": "TotalVoteScore",
"incr": args.score
},
{
"key": TotalVotePlayers,
"incr": 1
}
]
}
let notifyVote = false
let res = await server.IncrTitleData(reqData);
if (res.result == 0)
return "success"
else
return "failed"
}
案例2 :打开宝箱并获取随机金币
宝箱是许多游戏中常见的概念。打开宝箱会为玩家提供各种物品。让我们看看如何使用 PGOS 经济和扩展服务来打造一个包含随机金币的宝箱物品。
2.1 在 Web 门户上定义宝箱物品
在 Web 门户上创建宝箱物品并填写基本信息。确保该物品为“可消耗”物品,并为其分配一个虚拟服务器。
右侧是物品消耗后传递给虚拟服务器的示例参数。
2.2 使用虚拟服务器实现授予逻辑
下一步是编写代码,向玩家授予随机金币。
以下脚本分三步处理物品消费操作:
- 查询玩家钱包余额。
- 向玩家授予随机数量的金币。
- 再次查询钱包余额。
您可以通过在 Web 门户上查看虚拟服务器执行日志来确认整个过程。
"use strict";
const server = require('virtual-server-framework/api')
var {CustomError} = require('exception')
/**
* @author pgos
* @interface main_handler
* @description xxxxxx
* @time 2021.01.01
*/
exports.main_handler = async (args, context) => {
console.log("Hello World");
console.log(args);
console.log(context);
return args;
};
/**
* @author pgos
* @interface test
* @description xxxxxx
* @time 2021.01.01
*/
exports.test = async (args, context) => {
console.log("TEST");
console.log(args);
console.log(context);
throw new CustomError(999, "my err msg")
return args;
};
exports.InventoryTest = async function (args, context) {
var req = {"player_id":args.player_id}
var data = await server.GetPlayerCurrency(req)
console.log("GetPlayerCurrency", JSON.stringify(data))
req = {"player_id":args.player_id,
"granted_currency": {
"currency_code": "BTC",
"amount": Math.random()*10
}}
data = await server.GrantCurrencyToPlayer(req)
console.log("GrantCurrencyToPlayer", JSON.stringify(data))
data = await server.GetPlayerCurrency(req)
console.log("GetPlayerCurrency", JSON.stringify(data))
return data
}
3. 案例:实现简单的战斗赛季机制
链接至示例页面。
4. 案例:在第三方平台上监控DAU/PCU数据
大多数情况下,PGOS上发生的事件会保留在PGOS上。除了使用PGOS的虚拟服务器处理这些事件外,还可以在第三方平台上使用这些事件。
我们以监控DAU/PCU数据为例。
首先,创建一个Webhook并指定要发送HTTP请求的URL。
然后将 webhook 添加到 event_player_login_pgos
事件的操作中。
对 event_player_logout_pgos
事件执行相同操作。
配置后,玩家登录和注销数据将持续上报至 webhook 中指定的第三方平台。