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

More Documentation (Wowie!) #492

Merged
merged 17 commits into from
Oct 3, 2022
Merged
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"decompiling",
"Dependants",
"everytime",
"overridable",
"Untarget"
]
}
5 changes: 5 additions & 0 deletions docs/.markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"default": true,
"single-h1": false,
"line-length": false
}
38 changes: 38 additions & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Contributing

This file will go over how to get a local build of the docs working

## Requirements

First and foremost, install [Python 3.10](https://python.org/downloads), this guide will assume the python version on your PATH is 3.10, to check this run `python --version`.

## Installing Pipenv

Next up we need to install pipenv, this is an advanced package manager for python that provides some much needed improvements to pip.

```sh
python -m pip install pipenv --user
```

This will install pipenv to your user, meaning you'll be able to use it anywhere.

## Generating The Site

Now, head to the `docs` folder within OWML and run `pipenv sync --dev`, this will install all required packages.

Then, run `pipenv shell` to launch a sub-shell environment.

Finally, run `menagerie generate`, this will output the site to a folder called `out`.

## Viewing The Site

Now, head into the `out` folder and run `python -m http.server 8080`, this will start a web server in the out folder.

Finally, connect to `localhost:8080` with your browser, the website should be displayed.

After editing the site, you'll want to regenerate, I recommend you have two terminals open, one to generate, and the other to host the HTTP server.

## Getting Schemas

Schemas will not be in the site by default, to get them copy the schema in `Schemas` of the OWML folder and put it in `docs/content/pages/schemas` (you need to create the schemas folder). Do not commit this folder to git, as we only want to keep one copy of the schema in source control at once.

10 changes: 10 additions & 0 deletions docs/content/pages/404.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
Title: Page Not Found
Hide_In_Nav: True
Render_TOC: False
---

# Page Not Found

The page you requested could not be found.

63 changes: 63 additions & 0 deletions docs/content/pages/guides/apis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
Title: Creating APIs
Sort_Priority: 35
---

# Creating APIs

To allow for easy interoperability between mods, OWML provides an API system where mods can provide and consume APIs from eachother easily.

## Creating an API

To create an API start by making an interface with all the methods your api will have.

```csharp
public interface IMyCoolApi {
public string Echo(string input);
}
```

Now create a class that implements the API

```csharp
public class MyCoolApi : IMyCoolApi {
public string Echo(string input) => input;
}
```

Finally, override the `GetApi` method and have it return an instance of your API

```csharp
public class MyCoolMod : ModBehaviour {
public override object GetApi() {
return new MyCoolApi();
}
}
```

Your mod now provides the API to consumers!

## Consuming APIs

First, define the interface for the API, usually the mod will have it available somewhere to copy and paste.

```csharp
public interface IMyCoolApi {
public string Echo(string input);
}
```

Now, use `ModHelper.Interaction.TryGetModApi` to obtain the API for the mod.

```csharp
public class MyCoolMod : ModBehaviour {
public void Start() {
var myApi = ModHelper.TryGetModApi<IMyCoolApi>("Bwc9876.MyCoolMod");
ModHelper.Console.WriteLine(myApi.Echo("Hello, World!"));
}
}
```

!!! alert-warning "Warning"
Generic methods are not supported for mod APIs

7 changes: 6 additions & 1 deletion docs/content/pages/guides/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,24 @@ This file is used by OWML to generate the settings menu for your mod, we'll go o

This file tells Visual Studio about your project, it determines stuff like dependencies and versions, you shouldn't need to touch this.

## Viewing The C# File
## The ModBehaviour File

Double-click {YourProjectName}.cs, and it should open up in the main editor pane.

This file should contain a class that has the same name as your project and some methods within that class.

The class this class inherits from is `ModBehaviour`, which is a special `MonoBehaviour` that not only marks a class as the entry-point for a mod, but also provides various utilities and overridable methods.

We'll focus on `Start()`. In this method we do two things:

1. We output a message to the console alerting the user that the mod has loaded
2. We subscribe to the scene loaded event to output a message to the log when the SolarSystem scene is loaded.

You may have noticed we use the ModHelper field to achieve console output, ModHelper is a collection of utilities your mod can use to do a variety of things. It's covered in the "Mod Helper" section of the site.

!!! alert-warning "Warning"
There's only one `ModBehaviour` allowed per-mod, to add more components, you'll need to use `AddComponent<>` within your mod behaviour class.

## Building The Mod

Now that we know what the mod *should* do, let's make sure it does it. Building your mod should be as simple as pressing "Solution -> Build Solution" in the menu bar, if you get an error involving Visual Studio not being able to find a path, please see the section below, otherwise, skip to "Running The Mod"
Expand Down
16 changes: 12 additions & 4 deletions docs/content/pages/guides/mod_settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ First things first, you're going to need to define your settings, open up `defau
```json
{
"enabled": true,
"settings" {
"settings": {

}
}
Expand Down Expand Up @@ -45,13 +45,21 @@ You can also do other data types like numbers and strings
}
```

You can even make a selection field (where you can only select specific values) using arrays
You can even make a selection field (where you can only select specific values) using an object

```json
{
"enabled": true,
"settings": {
"Favorite Color": ["Purple", "Green", "Wrong >::("]
"Favorite Color": {
"type": "selector",
"value": "Green",
"options": [
"Purple",
"Green",
"Wrong >::("
]
}
}
}
```
Expand Down Expand Up @@ -81,7 +89,7 @@ If you want to listen for changes to your mod's config, you can override the `Co
public class MyMod : ModBehaviour {
public override void Configure(IModConfig config) {
var newFavorite = config.GetSettingsValue<string>("Favorite Food");
ModHelper.Console.WriteLine($"You changed your favorite food to: ${newFavorite}!");
ModHelper.Console.WriteLine($"You changed your favorite food to: {newFavorite}!");
}
}
```
8 changes: 6 additions & 2 deletions docs/content/pages/guides/patching.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ public class MyPatchClass {

Prefixes also allow you to completely stop the original method from running, to do so, make your method return a bool.

- If the boolean returned from the method is `true` the original method will be skipped
- If the boolean returned from the method is `false` the original method is still run
- If the boolean returned from the method is `true` the original method is still run
- If the boolean returned from the method is `false` the original method will be skipped

Let's say instead of simply logging when the player dies, we want to prevent it from happening entirely.

Expand Down Expand Up @@ -152,6 +152,7 @@ If you want to be able to access the actual object you're patching you can make
Let's say I want to log to the console where the Quantum Moon goes to every time it's observed:

```csharp
[HarmonyPatch]
public class MyPatchClass {
[HarmonyPostfix]
[HarmonyPatch(typeof(QuantumMoon), nameof(QuantumMoon.ChangeQuantumState))]
Expand All @@ -161,6 +162,9 @@ public class MyPatchClass {
}
```

!!! alert-info "How can we access that private field?"
OWML Publicizes all base-game assemblies for you, meaning you can get and set private fields and call private methods on base-game classes.

### Getting The Arguments Passed

If you need to get the arguments that were passed to a method inside your patch, you can simply have your method take arguments of the same name.
Expand Down
2 changes: 1 addition & 1 deletion docs/content/pages/guides/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ After the workflow finishes, head back to the "Code" tab and select "releases" o

Fill out the description with something like "First Release!", and press publish.

You've successfully creates a release on GitHub!
You've successfully created a release on GitHub!

## Adding Your Mod To The Database

Expand Down
4 changes: 4 additions & 0 deletions docs/content/pages/mod_helper/assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ public class MyCoolMod : ModBehaviour {
}
}
```

### Creating Asset Bundles

You can use [this unity project template](https://github.com/xen-42/outer-wilds-unity-template){target="_blank"} to make asset bundles, it includes stripped versions of all base-game scripts to make implementing base-game functionality easier.
7 changes: 5 additions & 2 deletions docs/content/pages/mod_helper/interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class MyCoolMod : ModBehaviour {

## TryGetModApi&lt;T&gt;

Attempts to get the API for the mod with the given unique name. You must define the mod's API as an interface and pass that in as the `T`. Returns `null` if the API couldn't be loaded.
Attempts to get the API for the mod with the given unique name. You must define the mod's API as an interface and pass that in as the `T`. Returns `null` if the API couldn't be loaded. To learn how to create and consume APIs, [check out our tutorial]({{ "Creating APIs"|route }})

```csharp
public class MyCoolMod : ModBehaviour {
Expand All @@ -76,7 +76,7 @@ public class MyCoolMod : ModBehaviour {

## ModExists

Checks if there exists a mod with the given uniqueName is installed and enabled.
Checks if a mod with the given uniqueName is installed and enabled.

```csharp
public class MyCoolMod : ModBehaviour {
Expand All @@ -86,3 +86,6 @@ public class MyCoolMod : ModBehaviour {
}
}
```

!!! alert-info "Tip"
If you don't want to check if the mod exists yourself, you can list the mod's uniqueName in [dependencies]({{ "Manifest Schema"|route }}#dependencies){class="link-info"} on your manifest, this will make the manager require the mod to be installed in order to start the game.