DiamondFire Object Notation Reference

DiamondFire Object Notation is a JSON-like language for constant data on DiamondFire plots. It is not a programming language. DFON was created to streamline the production of games with large amounts of constant, read-only data. It may be helpful for things like weapon stats, map regions, npc dialogue, etc.

It is recommended to have an understanding of JSON before using DFON, as they share many similarities. (I mean it!!)

Basic Structure

A DFON file uses the same rough structure as JSON. The file is one huge dictionary, which has 0 or more keys. Those keys contain other values like lists, strings, numbers, nested dictionaries, etc.

The outer-most dictionary is referred to as the "main dictionary." When DFON is compiled, each entry in the main dictionary will become a global variable. (With the corresponding name and value)

{ a: 0, b: 1, c: [1, 2, 3], "key": "whatever", }

This will compile down into a code-line that sets the global variables a, b, c, and key to their respective values.

Both strings and identifiers are allowed as keys for a dictionary, and trailing commas are allowed anywhere.
Values will be covered in the following three sections.

Basic Primitive Types

DFON has the common primitive value types from DiamondFire. This includes numbers, strings, text, locations, and vectors.
Numbers, strings, and text are covered in this section. The rest are covered in the next section.

Numbers are written in base-10, with or without a negative sign, and with or without a decimal place. A number's decimal place may go beyond 3 digits, unlike in DiamondFire - however the value will be truncated when compiling. Numbers additionally can have underscores anywhere inside of them for readability

Numbers may also be written in hex, octal, or binary using the 0x, 0o, and 0b prefixes. Numbers created this way do not support decimals.

All of the following are valid numbers: 12, -12, 12.52, -1_000_000_000.002, 0xFF_00_AA, -0b11101110, 0o77.



Strings are identical to JSON strings, except they can use either " or ' as a delimiter. Backslashes are used to escape characters.
Text is created by placing T before string quotes.

The following are valid strings: "", "Hello, World!", "String that has \na newline!"
The following are valid text: T"", T"<red>Hello, player!", "Text that has <newline>a newline!"

Remember that this is constant data! DiamondFire Codes like %default have no meaning.

Other Primitive Types

Locations are written as 3 or 5 comma-separated numbers inside of parenthesis.

Valid locations may look like: (1, 2, 3), (23.5, 50.5, 24.5, ), or (150.5, 200.5, 150.5, 0, 90, ).



Vectors are written as 3 comma-separated numbers inside of parenthesis.

Valid vectors may look like: <2, 3, 4> or <1, 0.25, 0, >.

Compound Types

DFON has the same two compound types as JSON, dictionaries and lists.
Lists are written as square brackets with zero or more comma-separated values inside. When compiled, they become a DiamondFire List value.

Valid lists may look like [], [2], or ["a", 2, { a: 2 }, ].



Dictionaries are written as curly braces with zero or more comma-separated key-value pairs inside. When compiled, they will become a DiamondFire Dictionary value. The main dictionary will compile differently than normal dictionary values, see above.

Valid dictionaries may look like {}, { a: 2 }, or { a: 2, b: { c: 3 }, }.

Documentation

DFON Files may be documented with comments. The language supports both inline and block comments using traditional C-style comments. Inline comments can be started with two slashes, block comments can be started with a slash-star, and ended with a star-slash.

{ // This is here for blablabla someVar: "whatever" /* This next section is here for yada yada yada... ... remember to blabla! */ }

Macros

Macros are where DFON strays away from mostly-normal JSON syntax. In any DFON file, any number of macros may be placed above the main dictionary. Macros have a name, zero or more named parameters, and a result expression. Both the macro name and parameter names must be valid identifiers.

Inside macros, parameter names can be used in place of regular values, which will be substituted with the argument supplied to the macro when it is invoked.

macro justATwo() = 2 macro pair(x, y) = [x, y] macro block(blockName, blockValue) = { "blockName": blockName, "miningSpeed": blockValue }

Note that in the third macro definition, the blockName key must be written as a string. Otherwise DFON would think that you're using the value of the blockName parameter as a dictionary key!

Assuming these macro definitions are properly above the main dictionary, they can now be invoked in place of a regular value. A macro can be invoked by writing its name followed by parenthesis, with comma-separated arguments between the parenthesis.

With the above code, writing justATwo() would be the same as writing 2.
Writing pair(1, 2) would be the same as writing [1, 2].
Finally, writing block("stone", 12) is identical to { blockName: "stone", miningSpeed: 12 }

Properly using macros can greatly reduce the size of DFON scripts, and improve readability.

Large Example

Sometimes it's easier to read through a large example.

/** * Macro to generate block data. * @param miningTime : number - The number of ticks to mine this block by hand * @param pickaxePower : number - The minimum required pickaxe power to mine this block * @param drops : string[] - List of item IDs this block can drop */ macro block(miningTime, pickaxePower, drops) = { "miningTime": miningTime, "pickaxePower": pickaxePower, "drops": drops } // Holds all game data { // Used for blockdata lookups dirMap: { east: < 1, 0, 0>, west: <-1, 0, 0>, north: < 0, 0, -1>, south: < 0, 0, 1>, up: < 0, 1, 0>, down: < 0, -1, 0>, }, // Stores mineable block information blockData: { 'stone': block(40, 0, ['stone']), 'andesite': block(60, 1, ['stone', 'iron_scrap', 'none']), 'cobblestone': block(80, 2, ['stone', 'gold_scrap', 'none']), }, }

This code, when compiled, creates two global variables: dirMap and blockData.

Compilation

Compiled DFON code will generate one process, and 0 or more functions. All generated templates need to be placed down to work. You will need to manually call the process when the first player joins the plot, there is no need to manually call the functions.

Limits

DFON isn't a good fit for every project. Using it means that any time you want to change data, you will need to edit the script, recompile the code, and replace the templates. This is made even harder if multiple people are working on your plot.

The main reasons to use DFON are to make constant data easier to read through and spot bugs with, as well as providing a sort of "backup" in case code is accidentally lost. Constant data is often more devastating to lose than a simple algorithm.

Feel free to get in contact if you'd like to suggest features or need help making your own PR. I am still currently thinking about implementation for function hooks, embedded metadata, support for all DF datatypes, and support for items, among other things.