0

I need to be able to dynamically deserialize strings (as properties) into classes during runtime. I also need to be able to do this in a way that supports nesting.

Example - Turret which shoots exploding bullets

Turret.yaml

Type: Turret
Name: MiniTurret
DisplayName: Mini Turret
MaxHP: 100
Damage: 50
TurretTurnSpeed: 20
Sprite: turret_1
ProjectileName: ExplosiveBullet

ExplosiveBullet.yaml

Type: Bullet
Name: ExplosiveBullet
DisplayName: Explosive Bullet
Damage: 50
TurretTurnSpeed: 20
Sprite: explosivebullet1
Components:
   - ExplosionComp:
      - ExplosionType: Incendiary
      - Damage: 10
      - Radius: 5

We're trying to create a turret (with the Turret.cs class, as stated in the "Type" field) that shoots projectiles with a Def name "ExplosiveBullet". At runtime, we deserialize the string "ExplosiveBullet" into it's appropriate class. The bullet now does the same with the list of Components - it needs to deserialize the string "ExplosionComp" into ExplosionComp.cs, and pass in the Damage and Radius values.

This way, I'm trying to created a nested component system which can reference other components (such as a turret referencing bullets, and a bullet referencing an explosion effect it causes when it's destroyed).

Does reflection have to be used to solve this? Is there anything built into YamlDotNet specifically to handle this?

I've seen dated or convoluted solutions; is there a good approach to handle this problem with YamlDotNet?

  • And what speaks against the component system that Unity already provides? Like what is your exact goal you are trying to solve? Why not simply have GameObject prefabs or ScriptableObjects? And why YAML (nothing against YAML in general but) why not e.g. JSON which is built-in supported and very wide spread -> a lot of material exists online – derHugo Jul 15 '21 at 16:03
  • In my game, I use tilemaps and will try to keep GameObject prefabs at a minimum. Scriptable objects would do the trick, but with YAML I can change something in the .yaml, save it, reload it in-game at runtime, and immediately see the changes without having to restart. YAML is also more modder friendly. I have nothing against JSON, I just think YAML looks nicer in general and should work the same way. Regardless of YAML or JSON, this is still a valid problem, and the game "RimWorld" uses this exact approach. – velkyalrie Jul 15 '21 at 16:21
  • Then maybe I don't quite understand what exactly your question is .. do you have s problem using `YamlDotNet` in general? Or is your question regarding the required data structure? – derHugo Jul 15 '21 at 16:24
  • The problem is using YamlDotNet, or in general a text based serialization format, to deserialize multiple objects of multiple classes in a single file – velkyalrie Jul 15 '21 at 16:27

1 Answers1

0

The YAML 1.2 Spec includes anchors, which allow you to create references to objects in one place and use them in another place.

However, that spec also makes it clear that YAML files are expected to be completely independent from one another. There's no standard way to reference one file's content from another.

I would recommend reading your YAML files into a Data Transfer Object layer, where you can allow simple string properties to contain references to other objects just by their unique ID. Then transform those DTOs into your object model layer by wiring up the object references to the objects created from the DTOs with the referenced IDs. It's a bit of a manual mapping process, but it provides for good separation of concerns.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • I've never heard of anchors or DTOs, therefore I don't know what this pattern even looks like or how to begin implementing it. Could you please update your answer with code for a complete beginner or point me to some resources on how to do this? Also, is this the only solution? Can't we use Reflection to build the classes at runtime? – velkyalrie Jul 15 '21 at 17:59
  • I don't really have time to elaborate much. A DTO is just a C# class whose properties directly mirror the structure of your YAML, so you can easily deserialize directly to a strongly-typed C# object. There are lots of other possible solutions: you could deserialize to a dictionary and write more manual code to map that into your model; you could write custom deserialization code (things like IYamlTypeConverter) to make certain properties like ProjectileName and ExplosionType cause other YAML files to get opened and deserialized. The sky's the limit. – StriplingWarrior Jul 15 '21 at 20:37
  • "Can't we use Reflection to build the classes at runtime?" That's what deserialization does. – StriplingWarrior Jul 15 '21 at 20:39