Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CORE] - Module Support #46

Open
LambdaSix opened this issue Feb 14, 2019 · 2 comments
Open

[CORE] - Module Support #46

LambdaSix opened this issue Feb 14, 2019 · 2 comments

Comments

@LambdaSix
Copy link
Owner

Framework out how to load modules into the core, file formats and directory layouts.

@LambdaSix
Copy link
Owner Author

LambdaSix commented Feb 14, 2019

mod_info.json:

{
	// Let the ModuleFactory claim this for loading.
	"type": "mod",
	// Unique internal ID for the mod
	"id": "example_mod_a",
	// Version identifier, used by the dependency manager
	"version": "1.1",
	// Long form description of the mod for users.
	"description": "Example mod with dependencies",
	// Author(s) of this mod.
	"authors": "A nony mouse",
	// Link to a forum post/github project
	"project_url": "http://github.com/Anonymouse/ExampleModA",
	// Dependencies of this mod, expressed as `<mod-id> {equalityOperator} <version>`
	"dependencies": [
		// Require Core at a minimum of version 1.0.1
		"core >= 1.0.1",
		// Require another mod at exactly version 1.0
		"example_mod_b == 1.0",
		// Optional dependency on another mod
		"? optiona_mod_c >= 1.0"
	],
	// Define any custom assemblies that should be loaded as part of module setup
	// All paths are relative to this file
	"assemblies": "lib/example_mod_a.dll",
	// Where to load JSON from
	"source_files": "json/",
	// Where to load any art files from (*client side only)
	"graphics_files": "gfx/"
}

@LambdaSix
Copy link
Owner Author

LambdaSix commented Feb 14, 2019

Load ordering

  • Load Core data files as templates + assemblies (data/core/mod_info.json ?)
  • Process abstracts for Core (don't allow overrides within core)
  • Find all data/mods/**/mod_info.json templates, load with ModuleManager
  • Organise mod load order by dependency graph
  • Foreach found module, load data files as templates + assemblies
  • Overriding happens here for each mod, since it's loaded after it's dependencies.
  • Finally start hydrating all templates via their factories.

Core Mod

'Core' is just defined as the content loaded by data/core/** as per the mod_info.json file contained there. The core mod is mandatory and usually desirable to set as a strict dependency of a mod.

While overrides will function within the Core mod, it isn't recommend to use it heavily due to internal load ordering, it should also be generally preferable to modify the item directly.

Abstracts

Abstracts are handled by a multi-pass approach to loading data, where first a template version containing the ID, Type, and some metadata, is loaded into a dictionary against it's JObject data container. Once all available data has been loaded as generic templates into DataFactory, the templates are hydrated into actual instances and made available for use by other systems.

Loading dependency chains of items (copy-from) is done by the responsible type factory, the general approach is to examine the item for a copy-from, and retrieve the item referred to, recursively until the root object is found, then they are loaded backwards to obtain the final object.
TypeLoaders take an existing object as a reference to support this by using the existing property value where either the new object's data container doesn't define the property or defines that it should be mutated.

Overrides

Overrides are handled after all data for dependencies has been loaded, each mod gets an opportunity to override existing templates of the same ID/Type with it's own, so while Core can override its own definitions, it should be preferred to just modify the original definition directly.

It's possible for a chain of mods to override the same item ID, the last mod (determined by dependencies) will be the winning override.

While overriding is intended to be a direct replacement of template data, it happens at a point where entities have been hydrated, so the original entity can be mutated by the overriding entity like as in copy-from, this is not strictly reliable due to the above chaining of overrides,

Mod Assemblies

Mod assemblies have access to nearly all the abilities that the core mod has:

  • Registering Services
  • Registering Systems
  • Introducing new Type loaders
  • Hooking parts of the engine runtime

Services

Services are intended to provide things accessible through the World instance, such as the ObjectManager which handles allocation of Serials to objects in the world, they are marked by use of the [ServiceData] attribute on their class definition.

Implement a Service if you want to provide something to other mods, or need a globally referable object.

All classes marked with this attribute loaded at world initialization, after all modules and data has been loaded. There are functions for registering manually.

Systems

Systems are registered with a Priority, choice of priority affects how often the system will be invoked via it's interface, IGameSystem.

Systems are intended for when you need something that will run every turn/tick or at some arbitrary interval between turns. An example of core usage of a system is the RadiationSimulationSystem which is invoked at least once every 20 turns and processes the world map for sources of radiation and emits a field out into the world. The WeatherSimulationSystem is another example that will use the arbitrary tick length to simulate weather patterns.

Registering a system as a Per Tick priority indicates it should be invoked every turn, be careful that you aren't doing too much in that update.

Handling Optional Mods

Where a mod dependency is marked as Optional, it's incumbent on the dependent mod to not assume the optional mod will be present, so override and copy-from should be avoided as they can't be guaranteed to be fulfilled.

Optional mods is more intended for something like a version checking mod, the code can query World.HasService<T>() to see if the desired service has been registered by the optional mod, then use it if available. It isn't intended for pure JSON mods as there can be no guarantees in every situation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant