27. Content support part 4: Game design data

You may need to use game data generated by planners to implement game logic. For example, item price or attribute data is not implemented with separate C++/C# classes for individual items, but depends on an item plan document read externally.

iFun Engine provides an interface called ResourceManager to read game data for cases such as this. Please go here for more details on relevant classes.

27.1. Reading design data

Design data can be JSON files, files with items delimited by tabs, or cases dependent on MySQL DBs.

27.1.1. If design data is a JSON file

Write the directory name where the JSON files will be located in MANIFEST.json as follows.

"ResourceManager": {
  "game_json_data_dir": "game_data"
}

iFun Engine reads JSON files inside the game_json_data_dir directory.

Important

Each file’s suffix must be one of json, txt, or text. Letter case does not matter.

Tip

game_json_data_dir is naturally included when the game server is packaged. For that reason, it is best to list not only in MANIFEST.json but also in the CMakeLists.txt RESOURCE_DIRS. For more details, please see Including game resource files in a package.

27.1.2. If design data is a tab-delimited file

Like JSON files, data files with each line delimited by tabs can be read. The MANIFEST.json settings are the same.

27.1.2.1. File requirements

Files must meet the following requirements.

27.1.2.1.1. Encoding and extensions
  • Files must be ASCII or UTF-8, and UTF-8 files must include BOM.
  • File extensions must be .txt or .text.
27.1.2.1.2. Comments
  • Lines beginning with // or # are comments.
27.1.2.1.3. Headers
  • The first line, excluding comments, is the header, and field names are listed and delimited by tabs.
27.1.2.1.4. Data
  • Lines after the header are data, and fields are listed and delimited by tabs.
  • The header and data must contain the same number of fields.
  • All spaces must be removed before and after each field.
  • If a data field with spaces removed is a null string, that field becomes a null JSON object.
  • Fields that are not null may be integers, real numbers, or text strings.

27.1.2.2. Converting JSON data

Files with the structure above may be converted to JSON data according to the following rules:

  • Each line is in the form {“header1”: “data1”, “header2”: “data2”}.
  • This converted line data makes up elements in a sequence.

Since they are converted to JSON to use in a game, use the ResourceManager::GetJsonData(...) function.

27.1.2.2.1. Example: Converting tab-delimited files to JSON

For example, if Item.txt is as follows, converted JSON will be as below.

// comment
// comment
Index   Name      Price   Description
0       힐링 포션   100.0    힐링해주는 포션. 힐링힐링~
1       단검        50.0    가장 기본이 되는 검.
[
  {
    "Index": 0,
    "Name": "힐링포션",
    "Price": 100.0,
    "Description": "힐링해주는 포션. 힐링힐링~"
  },
  {
    "Index": 1,
    "Name": "단검",
    "Price": 50.0,
    "Description": "가장 기본이 되는 검."
  }
]

27.1.3. If design data is in DB table form

27.1.3.1. MANIFEST.json settings

Configure MANIFEST.json as follows:

"ResourceManager": {
  "enable_game_data_mysql": true,
  "game_data_mysql_server": "tcp://localhost:3306",
  "game_data_mysql_username": "funapi",
  "game_data_mysql_password": "funapi",
  "game_data_mysql_database": "funapi",
  "game_data_mysql_tables": "game_data_table1,game_data_table2"
}

Input data are DB access data and DB table names to be read. Table names to be read are written in game_data_mysql_tables, and multiple tables can be listed and delimited by commas (,).

27.1.3.2. Converting JSON data

Each table can be converted into a JSON document using the following rules:

  • Table names become the JSON document file names.
  • Each row is converted into a JSON object in the form {“column1”: “data1”, “column2”: “data2”}.
  • This converted line data makes up elements in a sequence.

Use ResourceManager::GetJsonData(TABLE_NAME) to read values.

27.1.3.2.1. Example: Converting design data in a DB to JSON

If, for example, a DB table called Item is as follows, converted JSON will be as below.

mysql> select * from Item;
+-------+----------+-------+----------------------------+
| Index | Name     | Price | Description                |
+------------------+-------+----------------------------+
| 0     | 힐링 포션| 100.0 | 힐링해주는 포션. 힐링힐링~ |
| 1     | 단검     | 50.0  | 가장 기본이 되는 검.       |
+------------------+-------+----------------------------+
2 rows in set (0.00 sec)
[
  {
    "Index": 0,
    "Name": "힐링포션",
    "Price": 100.0,
    "Description": "힐링해주는 포션. 힐링힐링~"
  },
  {
    "Index": 1,
    "Name": "단검",
    "Price": 50.0,
    "Description": "가장 기본이 되는 검."
  }
]

27.2. Using design data

You can access JSON data to be read through ResourceManager::GetJsonData(...). In the example above, if the file is named Item.json, this JSON data can be called as follows:

Ptr<const Json> items = ResourceManager::GetJsonData("Item.json");
BOOST_ASSERT(items && items->IsArray());

for (size_t i = 0; i < items->Size(); ++i) {
  const Json &item = (*items)[i];
  LOG(INFO) << "item name: " << item["Name"].GetString();
  LOG(INFO) << "item price: " << item["Price"].GetDouble();
}
JToken items = ResourceManager.GetJsonData ("Item.json");
Log.Assert (items != null && items.Type == JTokenType.Array);

foreach (JObject item in items) {
  Log.Info ("item name: {0}", item["Name"].Value<string>());
  Log.Info ("item price: {0}", item["Price"].Value<double>());
}

27.3. Indexing design data

It is advantageous to index game data to be read in table form as key fields for easy access. iFun Engine provides a function called ResourceManager::IndexJsonArray(...) to do this.

Ptr<const IndexedJsonData> indexed_item_table;

bool MyGameServer::Install(const ArgumentMap &arguments) {
   ...
   Ptr<const Json> json = ResourceManager::GetJsonData("Item.json");
   indexed_item_table = ResourceManager::IndexJsonArray(*json, "Index");
   BOOST_ASSERT(indexed_item_table);
}

void OnItemUse(const Ptr<Session> &session, const Ptr<Json> &message) {
   ...
   int item_index = ...

   IndexedJsonData::const_iterator it = indexed_item_table->find(item_index);
   BOOST_ASSERT(it != indexed->end());
   const Json &item_info = *(it->second);

   int price = item_info["Price"].GetInteger();
   ...
}
public class Server
{
  Dictionary<int, JObject> the_indexed_item_table = null;

  public static void Install(ArgumentMap arguments)
  {
    ...
    JToken json = ResourceManager.GetJsonData ("data.json");

    the_indexed_item_table = ResourceManager.IndexJsonArray (
        (JArray) json, "Index");

    Log.Assert (indexed_item_table != null);
  }

  void OnItemUse(Session session, JObject message)
  {
    ...
    int item_index = ...
    JObject item_info = null;
    Log.Assert (the_indexed_item_table.TryGetValue(item_index, out item_info));

    int price = (int) data ["Price"];
    ...
  }
}

27.4. Design data parameters

  • game_json_data_dir: Directory path for game design data in JSON format. (type=string, default=””)
  • enable_game_data_mysql: Connection data for MySQL server containing game design data. (type=bool, default=false)
  • game_data_mysql_server: Connection data for MySQL server containing game design data. (type=string, default=”localhost:3306”)
  • game_data_mysql_username: Username for MySQL server containing game design data. (type=string, default=”funapi”)
  • game_data_mysql_password: Password for MySQL server containing game design data. (type=string, default=”funapi”)
  • game_data_mysql_database: Name of MySQL database containing game design data. (type=string, default=”game_data”)
  • game_data_mysql_character_set: Character set used to connect to game design database (type=string, default=”utf8”)
  • game_data_mysql_tables: Name of MySQL tables pertaining to game design data. Comma-separated. (type=string)