docs: Updates serialization docs (#1327)

This commit is contained in:
Kamron Batman 2023-02-02 19:37:18 -08:00 committed by GitHub
parent 8b3a2f9f5f
commit 1d376029dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 101 additions and 66 deletions

View file

@ -42,115 +42,140 @@ title: Serialization
```cs ```cs
public class ExampleItem : Item public class ExampleItem : Item
{ {
public string ExampleText { get; set; } private string _exampleText;
[Constructible] [CommandProperty(AccessLevel.GameMaster)]
public ExampleItem() : base(0) public string ExampleText
{ {
get => _exampleText;
set
{
if (value != _exampleText)
{
_exampleText = value;
this.MarkDirty();
}
}
}
} [Constructible]
public ExampleItem(Serial serial) : base(serial) public ExampleItem(string text) : base(0)
{ {
} Example = text;
}
public override void Serialize(IGenericWriter writer) public ExampleItem(Serial serial) : base(serial)
{ {
base.Serialize(writer); }
writer.WriteEncodedInt(0); //Version public override void Serialize(IGenericWriter writer)
writer.Write(ExampleText); {
} base.Serialize(writer);
public override void Deserialize(IGenericReader reader) writer.WriteEncodedInt(0); //Version
{ writer.Write(_exampleText);
base.Deserialize(reader); }
var version = reader.ReadEncodedInt(); public override void Deserialize(IGenericReader reader)
ExampleText = reader.ReadString(); {
} base.Deserialize(reader);
var version = reader.ReadEncodedInt();
// version 0
_exampleText = reader.ReadString();
}
} }
``` ```
Same class serialized with codegen Same class serialized with codegen
```cs ```cs
[Serializable(0)] [SerializationGenerator(0)]
public partial class ExampleItem : Item public partial class ExampleItem : Item
{ {
[SerializableField(0)] [SerializableField(0)]
public string ExampleText { get; set; } [SerializedCommandProperty(AccessLevel.GameMaster)]
private string _exampleText;
[Constructible] [Constructible]
public ExampleItem() : base(0) public ExampleItem(string text) : base(0)
{ {
_exampleText = text;
} }
} }
``` ```
### Step by step ### Step by step
1. Add ```SerializableAttribute(versionNumber)``` to your class and make it ```partial``` 1. Add ```SerializationGenerator(versionNumber)``` to your class and make the class ```partial```
```cs ```cs
[Serializable(0)] [SerializationGenerator(0)]
public partial class ExampleItem : Item public partial class ExampleItem : Item
``` ```
1. Delete constructors with ```Serial serial```, ```Serialize``` and ```Deserialize``` methods. 1. Delete the constructor with ```Serial serial```
1. Delete the ```Serialize``` and ```Deserialize``` methods.
1. Add ```SerializableField(fieldOrder)``` attribute to all field you want to serialize. 1. Add ```SerializableField(fieldOrder)``` attribute to all field you want to serialize.
```cs ```cs
[SerializableField(0)] [SerializableField(0)]
public string ExampleText { get; set; } private string _exampleText;
``` ```
1. Build project "Run Schema Migrations". ModernUO will create migration files for you. In this case "Server.Items.ExampleItem.v0.json" and "Server.Items.ExampleItem.Serialization.cs" 1. Run `publish.cmd`.
These files contains all information and classes needed for MUO to serialize/deserialize your objects.
ModernUO will create migration files for you. In this case "Server.Items.ExampleItem.v0.json" and "Server.Items.ExampleItem.Serialization.cs".
These files contains all information and classes needed for ModernUO to serialize/deserialize your objects.
### Migrations ### Migrations
When new field is added to serialization, you need to increment versionNumber and make migration files. Here is little example. When new field is added to the serialization, you need to increment `versionNumber` and run `publish.cmd` again to generate a migration file for the new version.
Here is little example.
New class code will look like this: New class code will look like this:
```cs ```cs
[Serializable(1)] [SerializationGenerator(1)]
public partial class ExampleItem : Item public partial class ExampleItem : Item
{ {
[SerializableField(0)] [SerializableField(0)]
public string ExampleText { get; set; } private string _exampleText;
[SerializableField(1)] [SerializableField(1)]
public string AddedExampleTest { get; set; } [SerializedCommandProperty(AccessLevel.GameMaster)]
private string _addedExampleTest;
[Constructible] [Constructible]
public ExampleItem() : base(0) public ExampleItem(string text, string addedText) : base(0)
{ {
} _exampleText = text;
_addedExampleTest = addedText;
}
} }
``` ```
After building "Run Schema Migrations" project, MUO will generate V0Content in serialization class. Your IDE (Visual Studio, Rider, or VSCode), will show errors and the ModernUO will not compile.
This happens because the code generator builds a migration from V0 to V1 and a new struct `V0Content` with all of the V0 fields is generated.
This Content contains all fields from V0. ModernUO is expecting the developer to create a migration from the old version to the new.
Now create MigrateFrom for each version you make, in this case V0. Now create a `MigrateFrom` method for each of the older versions, in this case V0, to the new version.
!!! Tip
When you have more versions, create standalone file for migrations only. For example "ExampleItem.Migrations.cs"
```cs ```cs
private void MigrateFrom(V0Content content) private void MigrateFrom(V0Content content)
{ {
ExampleText = content.ExampleText; _exampleText = content.ExampleText;
} }
``` ```
Your migration is now completed. !!! Tip
Since the class is `partial`, you can create a standalone file for migrations to keep them organized. For example "ExampleItem.Migrations.cs"
Your migration is now complete.
### Migrating from pre-codegen ### Migrating from pre-codegen
For migration from pre-codegen code, use method To migrate from pre-codegen serialization, change the old Deserialize method to this:
```cs ```cs
private void Deserialize(IGenericReader reader, int version) private void Deserialize(IGenericReader reader, int version)
``` ```
this method is called when codegen doesnt have VXContent for deserialized object or version of Content is lower than deserialized. This method will be automatically called when the serialization generator doesn't have a migration for for that older version.
In this method you can make old fashioned deserialization as before codegen. In this method you can make old fashioned deserializations that are mostly compatible with RunUO.
### After deserialization ### After Deserialization
For some code changes after world load, you can use AfterDeserializationAttribute. To execute code after the deserialization, add the `AfterDeserialization()` attribute to a method.
```cs ```cs
[AfterDeserialization] [AfterDeserialization]
private void AfterDeserialization() private void AfterDeserialization()
@ -159,5 +184,15 @@ title: Serialization
} }
``` ```
### Embedded serialization !!! Tip
Sometimes you need to serialize object inside object. For this you should use "EmbeddedSerializableAttribute". Nice example to understand it is ["AquariumState"](https://github.com/modernuo/ModernUO/blob/main/Projects/UOContent/Items/Aquarium/AquariumState.cs) By default, `AfterDeserialization` is executed synchronously right after the actual deserialization. Passing `false` to the attribute will make it execute after all deserializations.
### Serializing Non-Entity Classes
Sometimes you might need to serialize a nested object that is not an `ISerializable`. The syntax is largely the same except you must also mark the *parent* object for dirty tracking by using the `DirtyTrackingEntity` attribute.
A good example of this is ["AquariumState"](https://github.com/modernuo/ModernUO/blob/main/Projects/UOContent/Items/Aquarium/AquariumState.cs).
!!! Note
Non-entity classes cannot be serialized by reference since that would require a reference Serial or ID. This means if the object is a serializable property on multiple objects, it will be serialized
multiple times and will effectively get duplicated on world load. Consider either making it an `ISerializable` type and building world load/save mechanisms, or do not serialize the nested object directly.
Instead opt for a global lookup, serialize with generic persistence, and then reattach to the objects using the `WorldLoad` event sink.

View file

@ -9,7 +9,7 @@ edit_uri: edit/main/docs/
repo_name: modernuo/modernuo repo_name: modernuo/modernuo
repo_url: https://github.com/modernuo/modernuo repo_url: https://github.com/modernuo/modernuo
site_description: The Ultima Online Server Emulator for the modern era! site_description: The Ultima Online Server Emulator for the modern era!
copyright: Copyright 2019-2022 ModernUO Development Team copyright: Copyright 2019-2023 ModernUO Development Team
theme: theme:
name: material name: material
favicon: branding/favicon.png favicon: branding/favicon.png
@ -24,19 +24,19 @@ extra_css:
extra: extra:
social: social:
- icon: fontawesome/brands/github - icon: fontawesome/brands/github
link: https://github.com/modernuo/modernuo link: https://muo.gg/github
name: ModernUO on Github name: ModernUO on Github
- icon: fontawesome/brands/discord - icon: fontawesome/brands/discord
link: https://discord.gg/DHkNUsq link: https://muo.gg/discord
name: ModernUO on Discord name: ModernUO on Discord
- icon: fontawesome/brands/patreon - icon: fontawesome/brands/patreon
link: https://patreon.com/modernuo link: https://muo.gg/patreon
name: Sponsor ModernUO on Patreon name: Sponsor ModernUO on Patreon
- icon: fontawesome/brands/reddit - icon: fontawesome/brands/reddit
link: https://reddit.com/r/modernuo link: https://muo.gg/reddit
name: /r/modernuo name: /r/modernuo
- icon: fontawesome/brands/twitter - icon: fontawesome/brands/twitter
link: https://twitter.com/modernuo link: https://muo.gg/twitter
name: "@modernuo" name: "@modernuo"
markdown_extensions: markdown_extensions:
- admonition - admonition