Skip to content

Database

Hyomoto edited this page Oct 12, 2020 · 11 revisions

Database provides a JSON-like language, fastdb, for writing external files with the addition of many convenience features. There is support for static values, inheritance and templates, and the ability to specify custom data types easily, thus expanding it to meet your own needs. The data loads into a DsTree, which allows retrieval via string paths, i.e. database.get( "enemies.goblin.health" ). The module is perfect for large data sets, such as RPGs or strategy games, where tweaking values can be cumbersome. Database can be re-loaded during runtime, allowing you to make persistent changes and see them reflected immediately without recompiling. Looking values up by string also makes a database a perfect fit for localization and allows users to write their own easily. Lastly, if you wish to allow modding in your game, databases allow this with no extra effort on your part: simply making them available allows a user to edit them.

Dependencies: Core, File Handling(File), Logging(Logger)

Contents

Getting Started

Databases are built on trees that have branches and leaves. Since a database is just a DsTree, it is worthwhile to look over that data structure for all the details on how they can be used. A brief overview as it relates to databases is provided here.

Loading a database

The first argument in database_load() is the file to load, if no second argument is provided then a new DsTree will be created.

global.database = database_load( "my_database.db" )

Reloading a database

If you provide a DsTree as the second argument, then the database will be loaded into it. This can be used to load multiple files into the same DsTree, if desired (though unnecessary as fastdb provides a command for this), but will have the effect of re-loading the database if the same file is loaded a second time.

database_load( "my_database.db", global.database )

Accessing database contents

Since a database is just a DsTree, all of it's features are available. The first argument is the path, or key, of the value to retrieve. The second argument is optional, but is provided instead of undefined if the key was not found.

var _price = global.database.get( "items.potions.health.price", 0 );

Writing to the database

It is important to note that the set command is indiscriminate. It will simply walk/create the path and assign the value, which includes overwriting anything incompatible along the way. For example, if "potions" in this example were a number, it would be destroyed and replaced with a branch.

global.database.set( "items.potions.health.price", 10 );

Syntax Overview

fastdb is designed for large datasets, and thus provides a number of convenience features to make writing databases easier.

Comments

Both single-line // and block /**/ comments are supported.

/* this is
also a comment*/

Basic Syntax

Fastdb relies on two forms, directives and assignment. Assignment is a left-hand key, an equals sign, and a right-hand value and will make up the bulk of the database. These are the entries and values that you want to be read into the program. Here we are creating a simple database with three branches and one value, we could retrieve it with "items.weapons.sword.atk"

  weapons = {
    sword = { atk = 10 }
  }
}```
Directives lack an equals sign and typically have no right-hand component.  They provide extra flexibility and generally make databases easier to work with and more powerful.
```$include:items.weapons```
### Hash Directives
There is currently only one hash directive: #include.
#### Include
```#include characters/attributes.db```
The include directive will inject the given file, if it exists, into the database at the given point.  In this way, it is possible to write multiple separate files that will be compiled into a single database when called.
### Dollar Directives
There are three named dollar directives: datatype, include and template.  There is also one special "assignment" directive.
#### Datatype
By default, an undefined datatype will be read in as a number or a string based on context (whether it has been encapsulated in "'s).  However, if the $datatype directive is used, these entries will instead be passed to that data type for processing.  The type is separated by a :, and must be one that has been defined or an error will result.  If no type is provided, this will return processing to normal.
```$datatype:string
$datatype:```
#### Template
Sets a template for the current branch.  All new branches created from this one will be copied from the template entry.  Therefore, any template entries must be created before an entry that will inherit from it.  Here we will create a new "sword" entry that will contain one value "atk" that was inherited from "template.weapon"
```template.weapon = { atk = 10 }
$template:template.weapon
sword = {}```
#### Include
Much like template, $include will call for another entry to be copied into the current branch.  Here we perform the same activity as above, however the template is only included in "sword" and not "staff"
```template.weapon = { atk = 10 }
sword = { $include:template.weapon }
staff = {}```
#### Assignment Directive
The assignment directive is placed just before a right-hand value to specify what data type it should have.  By default, fastdb only recognizes strings and numbers, and thus must be told what to do with custom entries.  Out-of-the-box FAST provides two such assignment directives: link and array.
##### Array Datatype
Converts a comma separated list into an array.
```value = $array:0,1,2,3```
##### Link Datatype
Allows creating symbolic links to other places in the database.  Unlike templates, these will be created _after_ the database has finished processing, thus they can point to places that haven't been created yet.  Links can be traversed just like normal branches.
```foo = { bar = { key = 0 } }
link = $link:foo.bar```
### The @ symbol
It is possible to write constants for your database using the @ symbol.  These can be left-hand or right-hand arguments.  However, they do not persist after the database has been created: they are only used when it is being loaded.  In the following example we could change @foo and all other entries would be updated to match.
```@foo = 10
@bar = @foo + 10
foo = @bar
bar = @bar```
### The + symbol
It is possible to add constants together while the database is being loaded, however this is limited explicitly to numbers and will throw an error if used in another context.
## Writing a Database

## Structures
FileFAST( filename, \*read_only?, \*new? )
* filename - the name of the file to load
* read_only - default: false
* new - default: false, creates a new, blank FAST database file
```GML
var _file = new FileFAST( "database.db", true, false );

Implements File Handling: File.

FileFAST is used to format the human readable, and writable FAST database files into one the database loader can parse. It contains a database-specific StringFormatter, as well as support for comments and the #include file tag. Lastly, it wraps up the line data with information about which file and line it originally came from to provide better error reporting when problems are encountered while loading.

Methods

  • fragment( string, file, line ) - returns the format used when writing to this file
  • toString() - returns the last file and line read from, this may not reflect the parent file if an included entry was last read, used for debugging

Variables

  • FASTformatter - static, returns the StringFormatter used to parse the file.
  • name - returns the name of the file the last line read belonged to
  • line - returns the line of the file the last line read belonged to
  • includes - how many #include files were loaded into this FileFAST
Clone this wiki locally