Adding Content #
File architecture #
Two types of files make up the basics of adding and updating content in the Content Data system: protobuf files that define templates for content, and JSON files that populate these templates with specific content.
Content protos #
Content protos are the source of truth for content definitions. They provide a template for possible fields and attributes for each type of content.
JSON files #
These files populate the actual instances of protos with user-defined data. They must perfectly match proto definitions.
Adding content with protos and JSON files.
Steps for making new content #
The content addition process follows several steps, which we’ll cover in this section:
- Create the protos, which serve as templates for the JSON files
- Define the Content Handlers to handle databse migrations
- Add content with the JSON files
- Run the apply command to verify and generate a JSON package that services can read
Create the protos #
Edit or create any relevant protos in the 5-ext/ext-protos
folder. If you’re editing provided content files, this is where you put the customizable ext fields.
Be sure to only edit files in5-ext
! If you edit files in the1-protos
folder, it won’t work.
Define Content Handlers #
Content handlers are a type of plugin assigned within the metadata file to handle database migrations for live data. Every piece of content has an associated Content Handler.
Content Handlers are very important when doing live data migrations. Games that are in development where database data doesn’t need to be preserved and therefore can be wiped don’t require such data migrations, but any type of content data still requires a Content Handler for handling and accesing data. For more information, check out Data Migrations for Live Games.
ContentHandler
is the class responsible for validating, containing, and providing access to content protos.
- Custom content must have an associated custom-defined Content Handler.
Custom-defined Content Handlers can be created and populated in the relevant service directory within 5-ext/ext/src/main/kotlin
.
Create a custom Content Handler #
At minimum, Content Handlers must contain the class along with the following information:
the handler’s name and the fact that it’s a
ContentHandler
, along with the custom proto’s location, name, and its class:class [handler name]: ContentHandler<[package].[proto name]>( [package].[proto name]::class )
the
idFromProto
override that returns the proto IDoverride fun idFromProto(proto: [package].[proto name]): String { return proto.[id field] }
Once the Content Handler has been created, you must assign it in the metadata file nested under applyTriggers:
and include a verstionsToRetain:
field to determine how many different versions of this type of content should be stored in the database.
{
"applyTriggers": {
"contentHandler": "[Content Handler class name]"
},
"versionsToRetain": 1
}
Create the JSON files #
Create and populate the two required JSON src/
files with the desired content. You can use the init
command (in bash) to generate these files, or you can create them manually.
The two required files:
- a
<content-type>.json
file that contains the list of content objects using the templates from the protos and defining specific fields. - a
<content-type>.metadata
file that contains metadata information, such as a link to the Content Handler and a version incrementer.
Remember that JSON objects can represent nested messages, so make sure that they have all fields filled out, not just ext
fields.
Apply changes and validate #
Run the apply
command (in bash or RPC for dev-only) to verify data and generate a JSON package/
file that services can now read.
Do not make the package/
file yourself, as this would skip the validation step. We also recommend never editing package files manually.
Basic validation #
It’s easy to have typos or missing data, especially when working with nested protos. If you update your source of truth directly, you can potentially crash your game.
The apply
command makes sure that when new content is applied, it’s been validated. It checks that the JSON matches the proto schema directly. Invalid content will prevent changes from being applied, and will offer specific error details to give users the chance to fix content immediately.
In addition to the validation of proto schemas, you can write custom validation for protos, for example, if you’d like to verify that a specific field is never empty.
Cross-content validation #
Cross-content validation is also available.
For provided content, Pragma Engine validates content across nested IDs (outside of ext
) during the contentdata apply
command. Validation of custom content (across nested ext
s) can be added to a Content Handler under the validateExtWithAllContent
function.
To validate acrossext
fields in provided content, a new Content Handler must be written. The new Content Handler needs to inherit from the provided Content Handler to maintain non-ext
content validation.
The validateExtWithAllContent
function must contain these steps:
- Pull out relevant
contentData
from thecontentByType
map. The keys are strings of content types, so use the content type’s file name without the JSON extension. - Pull out nested content IDs from the exts.
- These must be stored in a
mutableSetOf<CorrespondingIds>()
.CorrespondingIds
is a class that holds theidToValidate
and theparentId
. This ensures error messages are clear to assist with debugging.
- These must be stored in a
- Check that nested IDs are valid.
- Confirm that IDs are all part of the relevant content data type using
ContentData.validateIds(idsToValidate: Set<CorrespondingIds>, contentType: String)
.
- Confirm that IDs are all part of the relevant content data type using