$listedit/$dictedit - apply $ operations to nested collections;
Long Summary:
All entities are now initially loaded as a list, and then are applied to the final dictionary one by one. Thus, mods can affect the same entity several times; mods can operate on the other mods' entities; mods can operate on their own entities.
All collections are deep-copied when inherited - prevents the same collection to appear in several entities, and fixes related bugs.
Added several entity-level operations - work for entity of any type.
"$derives" - additive inheritance from the list of entity IDs. All collection properties - lists and dictionaries - are merged, all child's value properties are untouched, all parents' value properties that aren't defined in a child are passed to a child.
"$priority" - sets the order, in which entities from a list are applied to the final dictionary. By default, all entities have their priority as 0, higher means "earlier". Entities with the same priority follow the same rules as previously - (core) > (mods), (file order) > (definitions in file from top to bottom).tThus, the previous loading order is preserved for everything that doesn't use this operation. Supports decimals (in case one needs to insert something in-between enities with priorities like "1" and "2". The known limitation is that it currently doesn't allow to put something in-between entities with the same $priority.
Note, that $priority" applies to the entity definition - specific EntityData parsed from JSON - rather than resulting game entity. Thus, it's possible to affect the order in which operations are applied.
Existing "extends" operation now can be defined as "$extends" ("extends", without "$" will work too for legacy reasons).
"$contentgroups" - allows to mark content with tags (for whatever purpose). Currently, the only usage is to prevent entities with a specific tag from loading. But with DLL modding, possibilities are many.
Overhauled property-level operations, and added several more. For clarity, will list all of them:
"$append"/"$prepend": list, appends/prepends a list of items to the original list property.
"$plus"/minus: number, modifies the specified number to the original number property.
"$add": dictionary, extends a dictionary with the specified properties.
"$remove": list, removes each element in the list from the original property, which can either be a list or a dictionary. Only string values can be removed from a list.
"$prefix": string, prepends a string to the original string property.
"$postfix": string, appends a string to the original string property.
"$replace": dictionary<string, string>, replaces first occurence of key string with value string.
"$clear": removes the property entirely, value doesn't matter.
"$listedit/$dictedit": dictionary, applies any of the $ operations (including this one) to the nested list or dictionary. List entries are targeted as strings with entry number, starting from zero. Examples:
"list_of_dictionaries$listedit": { "1$add": { "value": 1 } }
"dictionary$dictedit": { "nested_list$append": [ "value" ] }
Note that $ operations can't be inherited, and can't be modified by other $ operations.
All string operations are localizable, when applied to the localizable fields.
All list $ operations can now be defined as, let's call it, "unwrapped single-entry list", aka "simple value" - i.e. "$derives": [ "id" ] and "$derives": "id" are interpreted as the identical things.
Core content is loaded and processed the same way as mod content; in addition to being sensible and pleasant to look at, this enables core content to make use of all $ operations. Since current CS content doesn't make use of any of them, the actual behaviour doesn't change (and the loading time changes negligibly).
tl;dr:
Long Summary:
All entities are now initially loaded as a list, and then are applied to the final dictionary one by one. Thus, mods can affect the same entity several times; mods can operate on the other mods' entities; mods can operate on their own entities.
All collections are deep-copied when inherited - prevents the same collection to appear in several entities, and fixes related bugs.
Added several entity-level operations - work for entity of any type.
"$derives" - additive inheritance from the list of entity IDs. All collection properties - lists and dictionaries - are merged, all child's value properties are untouched, all parents' value properties that aren't defined in a child are passed to a child.
Example: { "id": "parent1", "dict": { "dictEntryOne": "parent" }, "list": [ "parent1" ], "valueOne": "parent" },
{ "id": "parent2", "dict": { "dictEntryTwo": "parent" }, "list": [ "parent2" ], "valueTwo": "parent" },
{ "id": "child", "$derives": [ "parent1", "parent2" ], "dict": { "dictEntryOne": "child", "dictEntryThree": "child" }, "valueOne": "child" },
This'll result in child having:
{ "id": "child", "dict": { "dictEntryOne": "child", "dictEntryTwo": "parent", "dictEntryThree": "child" }, "list": [ "parent1", "parent2", "child" ], "valueOne": "child", "valueTwo": "parent" }
"$priority" - sets the order, in which entities from a list are applied to the final dictionary. By default, all entities have their priority as 0, higher means "earlier". Entities with the same priority follow the same rules as previously - (core) > (mods), (file order) > (definitions in file from top to bottom).tThus, the previous loading order is preserved for everything that doesn't use this operation. Supports decimals (in case one needs to insert something in-between enities with priorities like "1" and "2". The known limitation is that it currently doesn't allow to put something in-between entities with the same $priority. Note, that $priority" applies to the entity definition - specific EntityData parsed from JSON - rather than resulting game entity. Thus, it's possible to affect the order in which operations are applied.
Existing "extends" operation now can be defined as "$extends" ("extends", without "$" will work too for legacy reasons).
"$contentgroups" - allows to mark content with tags (for whatever purpose). Currently, the only usage is to prevent entities with a specific tag from loading. But with DLL modding, possibilities are many.
Overhauled property-level operations, and added several more. For clarity, will list all of them: "$append"/"$prepend": list, appends/prepends a list of items to the original list property. "$plus"/minus: number, modifies the specified number to the original number property. "$add": dictionary, extends a dictionary with the specified properties. "$remove": list, removes each element in the list from the original property, which can either be a list or a dictionary. Only string values can be removed from a list. "$prefix": string, prepends a string to the original string property. "$postfix": string, appends a string to the original string property. "$replace": dictionary<string, string>, replaces first occurence of key string with value string. "$clear": removes the property entirely, value doesn't matter. "$listedit/$dictedit": dictionary, applies any of the $ operations (including this one) to the nested list or dictionary. List entries are targeted as strings with entry number, starting from zero. Examples: "list_of_dictionaries$listedit": { "1$add": { "value": 1 } } "dictionary$dictedit": { "nested_list$append": [ "value" ] }
Note that $ operations can't be inherited, and can't be modified by other $ operations. All string operations are localizable, when applied to the localizable fields.
All list $ operations can now be defined as, let's call it, "unwrapped single-entry list", aka "simple value" - i.e. "$derives": [ "id" ] and "$derives": "id" are interpreted as the identical things.
Core content is loaded and processed the same way as mod content; in addition to being sensible and pleasant to look at, this enables core content to make use of all $ operations. Since current CS content doesn't make use of any of them, the actual behaviour doesn't change (and the loading time changes negligibly).