Adapting the Code - v1 Data Structure

Let's take a look at how the objects ended up:

Table of Contents


erDiagram v0_Player { WalletAddress EthAddress string Name int Gold } v1_PlayerProfile { WalletAddress ExternalAddress PK string Name int Gold map_string Characters map_string Dungeons } v1_PlayerVault { WalletAddress ExternalAddress PK array_string Tiles array_string Packs }


In addition to the improvements made above in v0.1, we have also added a key (indicated by PK in the diagram) and arrays to track the characters and dungeons owned by the player.


There are no further changes here. We are just identifying the ExternalAddress as the key for this object. 



erDiagram v0_Character { string Name WalletAddress Owner ColorAttributes ColorAttributes float32 Power } v1_Character { string Id PK string Name FK WalletAddress Owner ColorAttributes ColorAttributes float32 Power int Gold } v1_CharacterLookup { string Name FK string Id PK }

The main functional change is that Characters can now hold Gold. If the only place a player has gold is in the PlayerProfile then every dungeon match (either as the player or dungeon owner) would cause a write to the PlayerProfile. With enough dungeons or characters this could cause conflicts. The player can collect Gold from their Characters and Dungeons as needed.

Another minor change is to make the Power property consistent as a float instead of an integer.

The last change is that characters are now keyed by a unique ID. They also have a name which is unique across all characters.

Character Lookup

This object is a reverse-lookup that will let us fetch the ID of a character based on their name. As we saw above, the PlayerProfile now stores the names of characters owned by players. This could probably be further improved to have the PlayerProfile store the Character ID instead of the name.



erDiagram v1_Pack { string Id PK string Collection WalletAddress Owner }

No change, except we're acknowledging the Id as the key for the chain.



erDiagram v0_Tile { TileType TileType ColorAttributes ColorAttributes WalletAddress Owner } v1_Tile { Id string PK TileType TileType ObjectStatus ObjectStatus ColorAttributes ColorAttributes WalletAddress Owner }

In the MVP code there was no connection between the tiles and the player that owned them - it was just hard-coded in memory. So we've added an ID to the tiles and we track those IDs in the PlayerVault object.

The other functional change is that we track the ObjectStatus of the tile. Currently we just use this to track whether the tile is In Use by a dungeon, but we may add more statuses so we're storing this as an "enum" instead of a boolean. When we implement trading or selling we will need to check this status to make sure tiles that are in use cannot be moved. 



erDiagram v0_Dungeon { WalletAddress Owner string Name int Width int Height int Power int Difficulty array_DungeonTile Tiles } v1_Dungeon { WalletAddress Owner PK string Name PK int Width int Height float32 Power int Difficulty int Gold array_DungeonTile Tiles } v1_DungeonTile { int X int Y string TileId }

The dungeon is our first case of of having a composite key. We're using the Owner's wallet and the name of the dungeon to establish a unique key. The reason we're not doing this with Characters is because it's quite likely that Characters will be traded between people so they need to have an ID that does not change. A dungeon is composed of tiles so it wouldn't be possible to trade a dungeon without also trading all of the tiles. This is possible, but less likely so for now we'll keep it simpler.

Similar to the Character object, we've added Gold into the Dungeon to decouple gold won from matches from the PlayerProfile.

Another minor change is to make the Power property consistent as a float instead of an integer.


This is a case where we take the Document Database approach: DungeonTiles are directly tied to the Dungeon they are created for so we store them as a single object. This means the DungeonTile object does not have a key. The contract manages marking the referenced Tiles as InUse when they are added into a Dungeon.


erDiagram v1_DungeonListing { WalletAddress Owner PK string Name PK ObjectStatus Status }

We've added a key to the DungeonListing similar to the Dungeon, and we track the status of it using the same enum as on the Tile object. This allows the contract to ensure a Dungeon is not in use when doing certain actions.


erDiagram v0_DungeonMatch { Dungeon Dungeon Character Character float32 DungeonMultiplier float32 CharacterMultiplier float32 StartingPower float32 EndingPower int Reward array_int PlayedTiles } v1_DungeonMatch { string DungeonOwner PK string DungeonName PK int64 StartTime PK int64 EndTime string CharacterName string Player float32 DungeonMultiplier float32 CharacterMultiplier float32 StartingPower float32 EndingPower int Reward array_int PlayedTiles }

This object has the most changes from the MVP code.

In-Memory References to Keys

The MVP code assumed we would have the Dungeon and Character for the match embedded in the object. We could take this approach by essentially writing an OR/M that would handle fetching and hydrating the full object, but this will add a lot of complexity and cause unnecessary performance hits which we want to avoid in blockchain contracts.

The contract takes on the complexity of fetching the Dungeon and Character objects by their composite keys when they are needed.

This object will be keyed by the Owner, Name, and StartTime.  The initial design does not allow the same DungeonMatch to be ran multiple times. Adding the start time to the key allows us to store multiple matches for the same dungeon.

Full Data

We have also added a StartTime and EndTime to fully track data about this match. These fields can be used to identify the status of a match (started or finished) as well as preserve the history for later.