#Is it worth using a JSON alternative?

1 messages · Page 1 of 1 (latest)

fickle palm
#

I've been using JSON for my project, which has been working totally fine for what I'm doing. I'm only really familiar with JSON, but I know other formats exist like YAML. It's always nice to keep my options open, and as I'm now starting to work on a new feature of the project, I wonder if an alternative could be convenient to use instead of JSON.

The JSON it would look something like this. I give this to my terrain generation system which uses it to create a heightmap which is used to create the mesh for the ground.

{
  "name": "Volcano Island Example",
  "default": true,
  "terrain": {
    "layers": [
      {
        "name": "Ocean",
        "order": 0,
        "effects": [
          {
            "name": "Flat Land",
            "operation": "Set Initial",
            "parameters": [
              {
                "name": "Height",
                "value": 0
              }
            ]
          },
          {
            "name": "Basic Noise",
            "operation": "Add",
            "parameters": [
              {
                "name": "Size",
                "value": 0.67
              },
              {
                "name": "Roughness",
                "value": 0.25
              },
              {
                "name": "Animation Speed",
                "value": 2.3
              }
            ]
          }
        ]
      },
      {
        "name": "Beach",
        "order": 1,
        "effects": [...]
      },
      {
        "name": "Grass",
        "order": 1,
        "effects": [...]
      },
      {
        "name": "Volcano",
        "order": 2,
        "effects": [...]
      },
      {
        "name": "Rivers",
        "order": 3,
        "effects": [...]
      }
    ]
  }
}```
#

Using JSON for this wouldnt be a problem, itd probably be convenient as ive already written tools that make it easy to parse data like this.
All I know is that some alternatives are designed to be more human readable. I think that could be useful as I'm probably going to be editing these presets by hand from time to time

vagrant sparrow
#

consider if you'll be manually authoring/editing/debugging these - if so, then maybe you'd want something more readable, like yaml

#

for alternate structures, consider the format/grouping of your data - that would make a choice between json or toml (though you can of course use either in any situation)

#

but bottom line, use what's comfortable/familiar to you

vagrant sparrow
fickle palm
#

toml looks interesting, I havent heard of that one before. Something I'm not a huge fan of in json is just how much space it would take up just for me to have that "Ocean" Layer. Which pretty much is a class like this

class Layer {
    string Name;
    int Order;
    Effect[] Effects;

    class Effect {
        string Name;
        Operation Type = Operation.SetInitial;
        EffectData Parameters; 
    }
}
vagrant sparrow
#

you can always just, not have whitespace?

#

and only prettify it when you need to view/edit it

fickle palm
#

well the size isnt like its a dealbreaker, I wouldnt avoid a format if it happens to have a lot of text

vagrant sparrow
#

json in transit/storage having unnecessary whitespace removed is a pretty common practice fwiw

fickle palm
#

I think Rider is set up to enforce the whitespace just to lay the files out right, I tried to pretty them before but it just removed those changes

#

I was curious what the Layer would look like if converted to yaml and toml

    - layerName: Ocean
      order: 0
      effects:
        - effectName: Flat Land
          operation: SetInitial
          parameters:
            - parameterName: Height
              value: 0
        - effectName: Basic Noise
          operation: Add
          parameters:
            - parameterName: Size
              value: 0.67
            - parameterName: Roughness
              value: 0.25
            - parameterName: AnimationSpeed
              value: 2.3```
```toml
[[terrain.layers]]
layerName = "Ocean"
order = 0

  [[terrain.layers.effects]]
  effectName = "Flat Land"
  operation = "SetInitial"

    [[terrain.layers.effects.parameters]]
    parameterName = "Height"
    value = 0

  [[terrain.layers.effects]]
  effectName = "Basic Noise"
  operation = "Add"

    [[terrain.layers.effects.parameters]]
    parameterName = "Size"
    value = 0.67

    [[terrain.layers.effects.parameters]]
    parameterName = "Roughness"
    value = 0.25

    [[terrain.layers.effects.parameters]]
    parameterName = "AnimationSpeed"
    value = 2.3```
#

its interesting to see how itd be with those

vagrant sparrow
#

if the parameters are unique, i'd probably look into making it somewhat of a dict (serialized as kv pairs instead of a list of homomorphic entries)

fickle palm
#
public abstract class BaseParam<T> : ITypedParam<T> {
    protected BaseParam(string name, T value) {
        Name = name;
        Value = value;
    }
    public string Name { get; }
    public T Value { get; set; }
}```Thats the actual class for the parameter
#

An effect could have many types of parameters depending on its function

vagrant sparrow
#

i mean the serialization

#

(though this could probably also move away from magic strings tbh)

fickle palm
#

magic strings?

vagrant sparrow
#

magic strings or magic numbers are specific strings/numbers hard-coded in

#

since they're not references, they're fragile - easy to break when making changes

#

it comes with a lot of flexibility, but also quite a bit of risk because most tools (built-in compiler checks or static analysis) won't be able to help you avoid mistakes

fickle palm
#

Ah, thats not a big problem for the system, this particular json is loaded in the Awake/Start phase just so an initial terrain gets generated.
Once thats done, its essentially cloned into the UI so you can go and alter its various parameters

#

I just want it to start out with an example terrain when you load the tool for the first time

vagrant sparrow
#

where/how are you using these parameters?

atomic tide
#

Personally I prefer JSON over both YAML and TOML

#

While technically YAML is a superset of JSON, but practically if you choose YAML you probably want to write it the YAML way, in which case there are some footguns like the Norway problem which makes YAML very error prone and arguably unusable without an IDE/linter.

#

TOML is designed to be a configuration format, so it's most suitable for flat data. While it does support deeply nested data, it's not supported well. You either have to accept a bunch of [[dot.concatenated.path.to.property.with.lots.of.brackets]], or you will just end up writing JSON.

#

And both YAML and TOML don't have nearly the amount of support as JSON in terms of de/serialization. You pretty much have to bring in a third party library to work with them programmatically.

fickle palm
#

Basically a means to set the property within a Compute Shader

vagrant sparrow
#

so these are used by reference later, right?

#

ah.

#

Compute Shader
yeah there's where the link only follows a magic string

#

but i guess that's unavoidable

fickle palm
#

I will have to address the flaws in how the effect/shaders are set up eventually, because that whole thing is built on magic values, its a little annoying creating new effects because of it

#

I wonder if this could be managed better as something like a json (or really any alternative, im not sure the generic name for that these formats are)

public class SlopeEffect : BaseEffect {
    SlopeEffect(List<IBaseControl> controls) : base("Slope", EffectType.Slope, controls) { }

    public static SlopeEffect CreateInstance() {
        var controls = new List<IBaseControl>
        {
            ControlFactory.ToggleControl("Reverse", false),
            ControlFactory.FloatSliderControl("Direction", 0f, 360f, 0f),
            ControlFactory.FloatSliderControl("Steepness", 0f, 1f, 1f)
        };
        return new SlopeEffect(controls);
    }

    public override void Draw() {
        base.Draw();
    }
}```
#

Maybe its just taking the problem and putting it into a new format, not actually fixing an underlying issue, but it might be helpful if I could store the entire library of Effects like this

{
  "name": "Slope Effect",
  "parameters": [
    { "name": "Reverse", "type": "bool", "default": false },
    { "name": "Direction", "type": "floatSlider", "min": 0, "max": 360, "default": 0 },
    { "name": "Steepness", "type": "floatSlider", "min": 0, "max": 1, "default": 1 }
  ]
}```I can do away with a base class, just have a single generic Effect that is given the text
fickle palm
atomic tide
#

I mean you can also just use TOML and write kind of like JSON instead of all the nested paths and brackets.

fickle palm
#

its interesting that its only JSON that has the brackets, the other two ditched them

atomic tide
#

For JSON:

{
    "pets": [
        { "type": "dog" },
        { "type": "cat" }
    ]
}

You can write it in TOML as:

[[pets]]
type = "dog"

[[pets]]
type = "cat"

Or you can write it in TOML as:

pets = [
    { type = "dog" },
    { type = "cat" }
]

But if you do the latter, then at that point I'm not sure if you are getting any benefit out of TOML than just writing JSON directly.

fickle palm
#

🤔 Maybe its not actually worth making a switch at this point. the JSON at the start of this post would be perfectly usable, and the EditorGUI is what displays that files contents so its not like it matters a whole lot whether its reading a .json or .toml or .yaml

#

But I think when it comes to cleaning up my implementation of Effects, TOML might be a nice format to configure the structure/content of them

[[effectConfigurations]]
name = "Foo Effect"

  [[effectConfigurations.parameters]]
  name = "Enabled"
  type = "bool"
  default = true```