Skip to content

Commit

Permalink
Merged two similar docs pages
Browse files Browse the repository at this point in the history
  • Loading branch information
Noggog committed Nov 6, 2024
1 parent 26426da commit 4d14d0b
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 87 deletions.
2 changes: 1 addition & 1 deletion docs/best-practices/FormLinks-Target-Getter-Interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ if (myTargetNpc.TryResolve(myLinkCache, out var npc))
// Found a INpc!
}
```
The `TryResolve` call wants to return an `INpc` type to you. But if all it can find is a [readonly `INpcGetter`](../plugins/Importing.md#read-only-mod-importing), it cannot pretend that it's settable, and so fails to match. This is the result of you asking the system to find an Npc that is settable, when the ones that exist are only getters.
The `TryResolve` call wants to return an `INpc` type to you. But if all it can find is a [readonly `INpcGetter`](../plugins/Importing-and-Construction.md#read-only-mod-importing), it cannot pretend that it's settable, and so fails to match. This is the result of you asking the system to find an Npc that is settable, when the ones that exist are only getters.

You can solve this issue by modifying the TryResolve scope:
```cs
Expand Down
2 changes: 1 addition & 1 deletion docs/best-practices/Read-Only.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ In most example code, APIs, and projects you look at the code will mostly be dea
The best practice is to convert from readonly interfaces to mutable version as late as possible. This allows the systems to avoid parsing the whole record when it's not applicable.

### Readonly Increases Speed
A lot of Mutagen's speed comes from short circuiting unnecessary work. A big way it does this is by exposing records via [Binary Overlays](../plugins/Importing.md). These are record objects that are very lightweight and fast. But one of their downsides is they are read only.
A lot of Mutagen's speed comes from short circuiting unnecessary work. A big way it does this is by exposing records via [Binary Overlays](../plugins/Importing-and-Construction.md). These are record objects that are very lightweight and fast. But one of their downsides is they are read only.

As soon as you want to modify something, you have to first convert it to a settable version of the record. This means creating a more "normal" settable `Npc` class, and reading ALL the data within that record to fill out each field one by one. This is often a waste of time.

Expand Down
2 changes: 1 addition & 1 deletion docs/loadorder/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ If you don't want a whole environment, and just want some convenience for import
var loadOrder = LoadOrder.Import<ISkyrimModGetter>(listings, GameRelease.SkyrimSE);
```
!!! tip "Prefer Getter Generic"
The choice of specifying Getter or Setter interfaces (`ISkyrimMod` vs `ISkyrimModGetter`) is important, as that will drive the style that the mods are imported with. If the Getter is specified, then the more optimized [Binary Overlay](../plugins/Importing.md#read-only-mod-importing) systems will be used. If Setter is specified, then all the import work will need to be done up front into a mutable object.
The choice of specifying Getter or Setter interfaces (`ISkyrimMod` vs `ISkyrimModGetter`) is important, as that will drive the style that the mods are imported with. If the Getter is specified, then the more optimized [Binary Overlay](../plugins/Importing-and-Construction.md#read-only-mod-importing) systems will be used. If Setter is specified, then all the import work will need to be done up front into a mutable object.

## Writing a Load Order
A `LoadOrder` can also export its contents to a file.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
## Importing
All Mods are generated with the ability to create themselves from their binary plugin format (esp/esm/esl).

## Mutable Mod Importing
## Read Only
The Binary Overlay imports mods in a readonly, on-demand fashion. Only fields that are accessed get parsed, which saves a lot of time and work.

```cs
using var mod = OblivionMod.CreateFromBinaryOverlay(pathToMod);
// Code accessing the mod
```

!!! tip "Preferred"
Use Binary Overlays when possible, up until you want to mutate records.

[:octicons-arrow-right-24: Mutation Patterns](../best-practices/Read-Only.md)

### No Up Front Work
With the overlay pattern, a mod object is returned almost immediately for use after having done almost no parsing. As the user accesses members of the `Mod`, the parsing is done on demand for only the members accessed.

### No Persistent References to Records or Memory
Binary Overlays keep no internal references to any record objects. This means that when a user is done working with something and discards it, the GC is allowed to immediately clean it up.

### Requires an Open Stream
Binary Overlays keep reference to an open stream internally, so they can read when accessed.

!!! info "Disposable"
Binary Overlay objects implement `IDisposable`. Putting them in `using` statements to close when appropriate is good practice.

### Best Practices

!!! warning "Avoid Repeated Access"
The Overlay pattern has the downside that repeated access of properties means repeated parsing of the same data.

[:octicons-arrow-right-24: Overlay Best Practices](../best-practices/Overlays-Single-Access.md)

## Mutable
A normal C# object can be created containing all of a mod's data. This is generally be reserved for when constructing or modifying records for output.

```cs
Expand Down Expand Up @@ -32,36 +65,45 @@ var mod = OblivionMod.CreateFromBinary(
This import call will only process and import Potions and NPCs.

!!! info "Generally Unused"
Generally this feature is unused, as [Binary Overlays](Importing.md#read-only-mod-importing) handle the situation of selectively accessing data much better.
Generally this feature is unused, as [Binary Overlays](Importing-and-Construction.md#read-only-mod-importing) handle the situation of selectively accessing data much better.

## Read Only Mod Importing
The Binary Overlay imports mods in a readonly, on-demand fashion. Only fields that are accessed get parsed, which saves a lot of time and work.
## Flexible Game Target
In more complex setups, often the game type is not known at compile time.

```cs
using var mod = OblivionMod.CreateFromBinaryOverlay(pathToMod);
// Code accessing the mod
```
=== "Untyped"
```cs
using var readOnlyInputMod = ModInstantiator.ImportGetter(pathToMod, release);
var mutableMod = ModInstantiator.ImportSetter(pathToMod, release);
```

!!! tip "Preferred"
Use Binary Overlays when possible, up until you want to mutate records.
=== "Generic"
```cs
var mod = ModInstantiator<TMod>.Importer(ModKey.FromFileName("MyMod.esp"), release);
```

[:octicons-arrow-right-24: Mutation Patterns](../best-practices/Read-Only.md)
!!! success "Dispose Appropriately"
Binary overlays are disposable, as they can keep streams open as they are accessed. Make sure to utilize `using` statements to dispose of them appropriately.

### No Up Front Work
With the overlay pattern, a mod object is returned almost immediately for use after having done almost no parsing. As the user accesses members of the `Mod`, the parsing is done on demand for only the members accessed.

### No Persistent References to Records or Memory
Binary Overlays keep no internal references to any record objects. This means that when a user is done working with something and discards it, the GC is allowed to immediately clean it up.
## Construction
How to make a new mod object from scratch without a file

### Requires an Open Stream
Binary Overlays keep reference to an open stream internally, so they can read when accessed.
### Known Game
If you know the game you will be working with at compile time, this is the typical way to create a new mod:

!!! info "Disposable"
Binary Overlay objects implement `IDisposable`. Putting them in `using` statements to close when appropriate is good practice.
``` cs
var newMod = new SkyrimMod(ModKey.FromFileName("MyMod.esp"), SkyrimRelease.SkyrimSE);
```

### Best Practices
### Unknown Game
In more complex setups, often the game type is not known at compile time

!!! warning "Avoid Repeated Access"
The Overlay pattern has the downside that repeated access of properties means repeated parsing of the same data.
=== "Untyped"
```cs
var newMod = ModInstantiator.Activator(ModKey.FromFileName("MyMod.esp"), release);
```

[:octicons-arrow-right-24: Overlay Best Practices](../best-practices/Overlays-Single-Access.md)
=== "Generic"
```cs
var newMod = ModInstantiator<TMod>.Activator(ModKey.FromFileName("MyMod.esp"), release);
```
59 changes: 0 additions & 59 deletions docs/plugins/Mod-Construction-and-Importing.md

This file was deleted.

3 changes: 1 addition & 2 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ nav:
- Plugin Record Suite:
- plugins/index.md
- ModKey, FormKey, FormLink: plugins/ModKey, FormKey, FormLink.md
- Importing: plugins/Importing.md
- Importing and Construction: plugins/Importing-and-Construction.md
- Exporting: plugins/Exporting.md
- Interfaces (Aspect/Link/Getters): plugins/Interfaces.md
- Copy Functionality: plugins/Copy-Functionality.md
Expand All @@ -72,7 +72,6 @@ nav:
- Asset Links: plugins/AssetLink.md
- Create, Duplicate, and Override: plugins/Create,-Duplicate,-and-Override.md
- Printing: plugins/Printing.md
- Mod Construction and Importing: plugins/Mod-Construction-and-Importing.md
- Abstract Subclassing: plugins/Abstract-Subclassing.md
- Specific Records:
- plugins/specific/index.md
Expand Down

0 comments on commit 4d14d0b

Please sign in to comment.