Creating the Battlepass Plugin #
In this section we’ll be creating the plugin that powers the battlepass logic and then registering it in the config.
Create an instanced item plugin #
First we’ll create a Pragma Engine plugin that initializes the battlepass and defines the leveling logic.
- Create a new directory at
5-ext/ext/src/main/kotlin/myDemo/inventory
. - Create a new Kotlin file in that directory called
MyInstancedItemPlugin.kt
. - Define a class that implements the
InstancedItemPlugin
interface:
package myDemo.inventory
import pragma.ExtError
import pragma.ExtException
import pragma.content.ContentDataNodeService
import pragma.inventory.*
import pragma.inventory.ext.*
import pragma.services.Service
@Suppress("unused", "UNUSED_PARAMETER")
class MyInstancedItemPlugin(service: Service, contentDataNodeService: ContentDataNodeService) : InstancedItemPlugin {
override suspend fun newInstanced(
instancedSpec: InventoryContent.InstancedSpec,
inventoryContent: InventoryServiceContent,
startingInventory: InventoryData,
pendingInventory: InventoryData,
clientRequestExt: ExtPurchaseRequest?,
serverRequestExt: ExtInstancedItemServerGrant?
): InstancedItemPlugin.InstancedItemPluginResult {
val extSpec: ExtInstancedSpec = instancedSpec.ext
val newItem = ExtInstancedItem.newBuilder()
if (extSpec.dataCase == ExtInstancedSpec.DataCase.BATTLEPASS_SPEC) {
val battlepass = Battlepass.newBuilder().setLevel(0).setXp(0)
newItem.setBattlepass(battlepass)
}
return InstancedItemPlugin.InstancedItemPluginResult(newItem.build())
}
override suspend fun update(
initialInstancedItem: InstancedItem,
instancedSpec: InventoryContent.InstancedSpec,
updateEntry: InventoryContent.UpdateEntry,
inventoryContent: InventoryServiceContent,
startingInventory: InventoryData,
pendingInventory: InventoryData,
clientRequestExt: ExtInstancedItemUpdate?,
serverRequestExt: ExtInstancedItemServerUpdate?
): InstancedItemPlugin.InstancedItemPluginResult {
val extSpec: ExtInstancedSpec = instancedSpec.ext
val extItem: ExtInstancedItem = initialInstancedItem.ext
val battlepassSpec: BattlepassSpec = extSpec.battlepassSpec
val battlepass = extItem.battlepass
// example for server battlepass update, because we trust incoming requests
// players should not be able to say "hey I'm going to give myself battlepass updates!"
// (clientRequestExt)
if (serverRequestExt != null) {
when (serverRequestExt.dataCase) {
ExtInstancedItemServerUpdate.DataCase.XP_UPDATE -> {
if (isBattlepassMaxedOut(battlepassSpec, battlepass)) {
return InstancedItemPlugin.InstancedItemPluginResult(extItem)
}
val instancedItemServerGrants = mutableListOf<InstancedItemServerGrant>()
val stackableItemGrants = mutableListOf<StackableItemGrant>()
var level = battlepass.level.toInt()
var xp = (battlepass.xp + serverRequestExt.xpUpdate.amount).toInt()
while (isLevelComplete(battlepassSpec, level, xp)) {
toPragmaReward(battlepassSpec.levelsList[level].rewardsList).apply {
instancedItemServerGrants += this.first
stackableItemGrants += this.second
}
if (!isMaxLevel(battlepassSpec, level)) {
xp -= getLevelXpToComplete(battlepassSpec, level)
level += 1
} else {
xp = getLevelXpToComplete(battlepassSpec, level)
break
}
}
val updatedBattlepass = battlepass.toBuilder().setXp(xp.toLong()).setLevel(level.toLong())
val updatedExt = extItem.toBuilder().setBattlepass(updatedBattlepass).build()
val inventoryModifications = InventoryModifications(
instancedItemServerGrants = instancedItemServerGrants,
stackableItemGrants = stackableItemGrants
)
return InstancedItemPlugin.InstancedItemPluginResult(updatedExt, inventoryModifications)
}
ExtInstancedItemServerUpdate.DataCase.DATA_NOT_SET -> {
throw ExtException(
ExtError.UNKNOWN_EXT_ERROR,
"serverRequestExt does not contain battlepass update information"
)
}
else -> throw Exception("shouldn't get here")
}
} else {
throw ExtException(
ExtError.UNKNOWN_EXT_ERROR,
"Cannot process this request"
) // client request, or at least server not provided
}
}
private fun isBattlepassMaxedOut(battlepassSpec: BattlepassSpec, battlepass: Battlepass): Boolean {
return isMaxLevel(battlepassSpec, battlepass.level.toInt()) &&
isLevelComplete(battlepassSpec, battlepass.level.toInt(), battlepass.xp.toInt())
}
private fun isMaxLevel(battlepassSpec: BattlepassSpec, level: Int): Boolean {
return level == battlepassSpec.levelsList.size - 1
}
private fun isLevelComplete(battlepassSpec: BattlepassSpec, level: Int, xp: Int): Boolean {
return xp >= getLevelXpToComplete(battlepassSpec, level)
}
private fun getLevelXpToComplete(battlepassSpec: BattlepassSpec, updatedLevel: Int) =
battlepassSpec.levelsList[updatedLevel].xpToComplete
private fun toPragmaReward(rewards: List<Reward>): Pair<List<InstancedItemServerGrant>, List<StackableItemGrant>> {
return rewards.fold(
mutableListOf<InstancedItemServerGrant>() to mutableListOf<StackableItemGrant>()
) { acc, it ->
when (it.itemCase) {
Reward.ItemCase.INSTANCED -> {
acc.first.add(
InstancedItemServerGrant(
ExtInstancedItemServerGrant.getDefaultInstance(),
it.instanced.catalogId,
listOf()
)
)
}
Reward.ItemCase.STACKABLE -> {
acc.second.add(
StackableItemGrant(it.stackable.catalogId, it.stackable.amount, listOf())
)
}
else -> {}
}
acc
}
}
}
Register the plugin #
- Open the
5-ext/config/local-dev.yml
config file. - Add the following to the
game
section of the config file:
pluginConfigs:
InventoryService.instancedItemPlugin:
class: "myDemo.inventory.MyInstancedItemPlugin"
Build #
Run make ext
using a terminal from the platform
directory.