Merge branch 'master' into no-more-CR

This commit is contained in:
Nick 2022-04-21 00:27:06 -04:00
commit a6e4911f41
68 changed files with 513 additions and 1670 deletions

2
.github/FUNDING.yml vendored
View File

@ -1,2 +1,2 @@
patreon: xen_42
patreon: ownh
custom: ["https://paypal.me/xen42"]

View File

@ -10,7 +10,7 @@ on:
pull_request:
paths:
- dev/**
- docs/**
- NewHorizons/*schema*.json
- NewHorizons/*.xsd
@ -22,9 +22,8 @@ on:
default: "/"
env:
OUT_DIR: ${{ github.events.inputs.relative_path }}
BASE_URL: https://nh.outerwildsmods.com/
PIPENV_VENV_IN_PROJECT: enabled
URL_PREFIX: ${{ github.events.inputs.relative_path }}
PIPENV_VENV_IN_PROJECT: 1
jobs:
build:
@ -33,11 +32,13 @@ jobs:
steps:
- uses: actions/checkout@v2
- run: mkdir ./.venv
- run: cp -r docs/** .
- if: github.ref == 'refs/heads/master'
run: |
echo "OUT_DIR=/" >> $GITHUB_ENV
echo "URL_PREFIX=/" >> $GITHUB_ENV
- name: Cache Dependencies
uses: actions/cache@v2
@ -51,26 +52,21 @@ jobs:
- name: Install dependecies
uses: VaultVulp/action-pipenv@v2.0.1
with:
command: install
command: install --dev
- name: Copy Schemas
run: |
mkdir content/schemas/
cp NewHorizons/schema.json content/schemas/
cp NewHorizons/star_system_schema.json content/schemas/
cp NewHorizons/translation_schema.json content/schemas/
cp NewHorizons/shiplog_schema.xsd content/schemas/
cp NewHorizons/dialogue_schema.xsd content/schemas/
- name: Create Output Dir
run: |
mkdir out/
mkdir out/schemas/
mkdir content/pages/schemas/
cp NewHorizons/schema.json content/pages/schemas/
cp NewHorizons/star_system_schema.json content/pages/schemas/
cp NewHorizons/translation_schema.json content/pages/schemas/
cp NewHorizons/shiplog_schema.xsd content/pages/schemas/
cp NewHorizons/dialogue_schema.xsd content/pages/schemas/
- name: Build Site
uses: VaultVulp/action-pipenv@v2.0.1
with:
command: run python generate.py
command: run python -m menagerie generate
- name: Upload Artifact
uses: actions/upload-artifact@v2

4
.gitignore vendored
View File

@ -412,3 +412,7 @@ NewHorizons/Properties/**
docs/out/**
docs/content/schemas/**
docs/schemas/**
# Unity project
new-horizons-unity
new-horizons-unity/**

Binary file not shown.

View File

@ -0,0 +1,7 @@
ManifestFileVersion: 0
CRC: 920416521
AssetBundleManifest:
AssetBundleInfos:
Info_0:
Name: shader
Dependencies: {}

Binary file not shown.

View File

@ -1,16 +1,17 @@
ManifestFileVersion: 0
CRC: 2524157958
CRC: 1131808909
Hashes:
AssetFileHash:
serializedVersion: 2
Hash: 882ab688c937b5592f590a313cfc0529
Hash: 183a5bb48d2c1afa94657b52eb300f40
TypeTreeHash:
serializedVersion: 2
Hash: 6370d3f9de9eca57f523bce048404a46
Hash: 55d48f4ad9c3b13330b9eb5ee5686477
HashAppended: 0
ClassTypes:
- Class: 48
Script: {instanceID: 0}
SerializeReferenceClassIdentifiers: []
Assets:
- Assets/Shaders/SphereTextureWrapper.shader
- Assets/Shaders/Ring.shader

View File

@ -82,9 +82,9 @@ namespace NewHorizons.Builder.Atmosphere
RotateTransform topRT = cloudsTopGO.AddComponent<RotateTransform>();
topRT.SetValue("_localAxis", Vector3.up);
topRT.SetValue("degreesPerSecond", 10);
topRT.SetValue("randomizeRotationRate", false);
topRT._localAxis = Vector3.up;
topRT._degreesPerSecond = 10;
topRT._randomizeRotationRate = false;
GameObject cloudsBottomGO = new GameObject();
cloudsBottomGO.SetActive(false);
@ -94,7 +94,7 @@ namespace NewHorizons.Builder.Atmosphere
TessellatedSphereRenderer bottomTSR = cloudsBottomGO.AddComponent<TessellatedSphereRenderer>();
bottomTSR.tessellationMeshGroup = GameObject.Find("CloudsBottomLayer_GD").GetComponent<TessellatedSphereRenderer>().tessellationMeshGroup;
var bottomTSRMaterials = GameObject.Find("CloudsBottomLayer_GD").GetComponent<TessellatedSphereRenderer>().sharedMaterials;
var bottomTSRMaterials = GameObject.Find("CloudsBottomLayer_QM").GetComponent<TessellatedSphereRenderer>().sharedMaterials;
var bottomTSRTempArray = new Material[bottomTSRMaterials.Length];
// It's a bit too green
@ -112,7 +112,7 @@ namespace NewHorizons.Builder.Atmosphere
bottomTSR.LODRadius = 1f;
TessSphereSectorToggle bottomTSST = cloudsBottomGO.AddComponent<TessSphereSectorToggle>();
bottomTSST.SetValue("_sector", sector);
bottomTSST._sector = sector;
GameObject cloudsFluidGO = new GameObject();
cloudsFluidGO.SetActive(false);
@ -125,15 +125,15 @@ namespace NewHorizons.Builder.Atmosphere
fluidSC.radius = atmo.Size;
OWShellCollider fluidOWSC = cloudsFluidGO.AddComponent<OWShellCollider>();
fluidOWSC.SetValue("_innerRadius", atmo.Size * 0.9f);
fluidOWSC._innerRadius = atmo.Size * 0.9f;
CloudLayerFluidVolume fluidCLFV = cloudsFluidGO.AddComponent<CloudLayerFluidVolume>();
fluidCLFV.SetValue("_layer", 5);
fluidCLFV.SetValue("_priority", 1);
fluidCLFV.SetValue("_density", 1.2f);
fluidCLFV.SetValue("_fluidType", FluidVolume.Type.CLOUD);
fluidCLFV.SetValue("_allowShipAutoroll", true);
fluidCLFV.SetValue("_disableOnStart", false);
fluidCLFV._layer = 5;
fluidCLFV._priority = 1;
fluidCLFV._density = 1.2f;
fluidCLFV._fluidType = FluidVolume.Type.CLOUD;
fluidCLFV._allowShipAutoroll = true;
fluidCLFV._disableOnStart = false;
// Fix the rotations once the rest is done
cloudsMainGO.transform.localRotation = Quaternion.Euler(0, 0, 0);

View File

@ -71,26 +71,32 @@ namespace NewHorizons.Builder.ShipLog
{
XElement curiosityName = entryElement.Element("Curiosity");
XElement id = entryElement.Element("ID");
if (curiosityName != null && id != null && _entryIdToRawName.ContainsKey(id.Value) == false)
if (id != null)
{
entryIDs.Add(id.Value);
_entryIdToRawName.Add(id.Value, curiosityName.Value);
if (curiosityName != null && _entryIdToRawName.ContainsKey(id.Value) == false)
{
_entryIdToRawName.Add(id.Value, curiosityName.Value);
}
}
foreach (XElement childEntryElement in entryElement.Elements("Entry"))
{
XElement childCuriosityName = childEntryElement.Element("Curiosity");
XElement childId = childEntryElement.Element("ID");
if (childId != null && _entryIdToRawName.ContainsKey(childId.Value))
if (childId != null)
{
if (childCuriosityName == null && curiosityName != null)
{
_entryIdToRawName.Add(childId.Value, curiosityName.Value);
}
else if (childCuriosityName != null)
{
_entryIdToRawName.Add(childId.Value, childCuriosityName.Value);
}
entryIDs.Add(childId.Value);
if (_entryIdToRawName.ContainsKey(childId.Value))
{
if (childCuriosityName == null && curiosityName != null)
{
_entryIdToRawName.Add(childId.Value, curiosityName.Value);
}
else if (childCuriosityName != null)
{
_entryIdToRawName.Add(childId.Value, childCuriosityName.Value);
}
}
}
AddTranslation(childEntryElement);
}

View File

@ -342,7 +342,6 @@ namespace NewHorizons.Components
private void Update()
{
Logger.Log("???");
_warpPrompt.SetVisibility(IsWarpDriveAvailable());
}
}

View File

@ -8,7 +8,8 @@
<xs:element name="NameField" type="xs:string">
<xs:annotation>
<xs:documentation>
The name of the dialogue tree
The name of the character, used for the interaction prompt. Set to `SIGN` for the prompt
"Read", or `RECORDING` for "Play Recording"
</xs:documentation>
</xs:annotation>
</xs:element>
@ -22,7 +23,7 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- Dialogue Node Info -->
<xs:complexType name="DialogueNode">
<xs:sequence>
@ -36,14 +37,8 @@
<xs:element name="EntryCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
The condition that needs to be met in order to get to this node
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="DialogueTargetShipLogCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
A ship log fact that must be revealed in order to get to this node
The condition that needs to be met in order for the dialogue to begin at this node. There must
be one node that has a value of `DEFAULT`
</xs:documentation>
</xs:annotation>
</xs:element>
@ -54,23 +49,53 @@
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="RevealFacts" type="RevealFacts" minOccurs="0">
<xs:annotation>
<xs:documentation>
Facts to reveal when the player sees this dialogue node
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="DialogueOptionsList" type="DialogueOptionsList" minOccurs="0">
<xs:annotation>
<xs:documentation>
A list of options to show to the player once the character is one talking
A list of options to show to the player once the character is done talking
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="RevealFacts" type="RevealFacts" minOccurs="0">
<xs:annotation>
<xs:documentation>
Facts to reveal when the player goes through this dialogue node
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="SetCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Set a new condition that will only last for the current loop
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="SetPersistentCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Set a new persistent condition that will last indefinitely in the current save, unless cancelled
or deleted
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="DialogueTargetShipLogCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
A ship log fact that must be revealed in order to proceed to the `DialogueTarget`
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="DialogueTarget" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
The name of the `DialogueNode` to go to after this node. Mutually exclusive with
`DialogueOptionsList` here
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<!-- Dialogue Info -->
<xs:complexType name="Dialogue">
<xs:sequence>
@ -83,7 +108,7 @@
</xs:element>
</xs:sequence>
</xs:complexType>
<!-- Reveal Facts Info -->
<xs:complexType name="RevealFacts">
<xs:sequence>
@ -96,7 +121,7 @@
</xs:element>
</xs:sequence>
</xs:complexType>
<!-- Dialogue Options List Info -->
<xs:complexType name="DialogueOptionsList">
<xs:sequence>
@ -109,21 +134,42 @@
</xs:element>
</xs:sequence>
</xs:complexType>
<!-- Dialogue Option Info -->
<xs:complexType name="DialogueOption">
<xs:sequence>
<xs:element name="RequiredPersistentCondition" type="xs:string" minOccurs="0">
<xs:element name="RequiredPersistentCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Require a prior condition to be met to show this option
Require a persistent condition to be met to show this option
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="CancelledPersistentCondition" type="xs:string" minOccurs="0">
<xs:element name="CancelledPersistentCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Hide this option if a condition has been met
Hide this option if a persistent condition has been met
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="RequiredCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Require a (single-loop) condition to be met to show this option
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="CancelledCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Hide this option if a (single-loop) condition has been met
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="RequiredLogCondition" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Require a ship log fact to be known to show this option
</xs:documentation>
</xs:annotation>
</xs:element>
@ -134,14 +180,27 @@
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="DialogueTarget" type="xs:string">
<xs:element name="ConditionToSet" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
The name of the DialogueNode to go to when this option is selected
Set a condition when this option is chosen
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="ConditionToCancel" type="xs:string" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Cancel a condition when this option is chosen
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="DialogueTarget" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
The name of the `DialogueNode` to go to when this option is selected
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
</xs:schema>

View File

@ -3,7 +3,7 @@
"author": "xen, Idiot, & Book",
"name": "New Horizons",
"uniqueName": "xen.NewHorizons",
"version": "0.10.2",
"version": "0.10.3",
"owmlVersion": "2.1.0",
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "Vesper.OuterWildsMMO", "Vesper.AutoResume" ],
"pathsToPreserve": [ "planets", "systems", "translations" ]

View File

@ -1,5 +1,9 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$schema": "https://json-schema.org/draft-07/schema",
"$docs": {
"title": "Celestial Body Schema",
"description": "Schema for a celestial body in New Horizons"
},
"$defs": {
"vector3": {
"type": "object",
@ -122,9 +126,14 @@
},
"destroy": {
"type": "boolean",
"description": "True if you want to delete this planet",
"description": "`true` if you want to delete this planet",
"default": false
},
"childrenToDestroy": {
"type": "string",
"description": "A list of paths to child GameObjects to destroy on this planet",
"default": []
},
"Base": {
"type": "object",
"properties": {
@ -136,7 +145,7 @@
"hasAmbientLight": {
"type": "boolean",
"default": false,
"description": "If the dark side of the body should have some slight ammount of light"
"description": "If the dark side of the body should have some slight amount of light"
},
"surfaceGravity": {
"type": "number",
@ -213,7 +222,7 @@
},
"cloudTint": {
"$ref": "#/$defs/color",
"description" : "Colour of the cloud layer. Only relevant if \"cloud\" has a value"
"description": "Colour of the cloud layer. Only relevant if \"cloud\" has a value"
},
"cloud": {
"type": "string",
@ -230,7 +239,7 @@
"useBasicCloudShader": {
"type": "boolean",
"default": false,
"description": "Set to false to use Giant's deep shader. Set to true to just apply the cloud texture as is."
"description": "Set to `false` in order to use Giant's deep shader. Set to `true` to just apply the cloud texture as is."
},
"shadowsOnClouds": {
"type": "boolean",
@ -245,7 +254,7 @@
"type": "number",
"minimum": 0,
"maximum": 1,
"description" : "How dense the fog is, if you put fog."
"description": "How dense the fog is, if you put fog."
},
"fogSize": {
"type": "number",
@ -263,7 +272,7 @@
"hasOxygen": {
"type": "boolean",
"default": false,
"description" : "Lets you survive on the planet without a suit."
"description": "Lets you survive on the planet without a suit."
},
"hasAtmosphere": {
"type": "boolean",
@ -311,7 +320,7 @@
},
"argumentOfPeriapsis": {
"$ref": "#/$defs/angle",
"description": "An angle (in degrees) defining the location of the periapsis (closest distance to it's primary body) if it has nonzero eccentricity."
"description": "An angle (in degrees) defining the location of the periapsis (the closest distance to it's primary body) if it has nonzero eccentricity."
},
"trueAnomaly": {
"$ref": "#/$defs/angle",
@ -333,7 +342,7 @@
},
"alignmentAxis": {
"$ref": "#/$defs/vector3",
"description": "If it is tidally locked, this direction will face towards the primary. Ex) Interloper uses 0, -1, 0. Most planets will want something like -1, 0, 0."
"description": "If it is tidally locked, this direction will face towards the primary. Ex: Interloper uses `0, -1, 0`. Most planets will want something like `-1, 0, 0`."
},
"showOrbitLine": {
"type": "boolean",
@ -363,7 +372,7 @@
"type": "number",
"default": 0,
"minimum": 0,
"description" : "Inner radius of the disk "
"description": "Inner radius of the disk "
},
"outerRadius": {
"type": "number",
@ -373,11 +382,11 @@
"inclination": {
"type": "number",
"default": 0,
"description" : "Angle between the rings and the equatorial plane of the planet."
"description": "Angle between the rings and the equatorial plane of the planet."
},
"longitudeOfAscendingNode": {
"$ref": "#/$defs/angle",
"description" : "Angle defining the point where the rings rise up from the planet's equatorial plane if inclination is nonzero."
"description": "Angle defining the point where the rings rise up from the planet's equatorial plane if inclination is nonzero."
},
"texture": {
"type": "string",
@ -386,11 +395,11 @@
"rotationSpeed": {
"type": "number",
"default": 0,
"description" : "Allows the rings to rotate."
"description": "Allows the rings to rotate."
},
"curve": {
"$ref": "#/$defs/curve",
"description" : "Allows the rings to grow/shrink with time."
"description": "Allows the rings to grow/shrink with time."
}
}
},
@ -408,12 +417,12 @@
"minHeight": {
"type": "number",
"minimum": 0,
"description" : "The lowest points on your planet will be at this height."
"description": "The lowest points on your planet will be at this height."
},
"maxHeight": {
"type": "number",
"minimum": 0,
"description" : "The highest points on your planet will be at this height."
"description": "The highest points on your planet will be at this height."
}
}
},
@ -435,11 +444,11 @@
},
"inclination": {
"$ref": "#/$defs/angle",
"description" : "Angle between the rings and the equatorial plane of the planet."
"description": "Angle between the rings and the equatorial plane of the planet."
},
"longitudeOfAscendingNode": {
"$ref": "#/$defs/angle",
"description" : "Angle defining the point where the rings rise up from the planet's equatorial plane if inclination is nonzero."
"description": "Angle defining the point where the rings rise up from the planet's equatorial plane if inclination is nonzero."
},
"randomSeed": {
"type": "integer",
@ -458,7 +467,7 @@
"type": "number",
"default": 2000,
"minimum": 0,
"description" : "Radius of the star."
"description": "Radius of the star."
},
"tint": {
"$ref": "#/$defs/color",
@ -481,11 +490,11 @@
"hasAtmosphere": {
"type": "boolean",
"default": true,
"description" : "The default sun has its own atmosphere that is different from regular planets. If you want that, set this to true."
"description": "The default sun has its own atmosphere that is different from regular planets. If you want that, set this to true."
},
"curve": {
"$ref": "#/$defs/curve",
"description" : "Allows the star to shrink/grow over time."
"description": "Allows the star to shrink/grow over time."
}
}
},
@ -606,7 +615,11 @@
"properties": {
"revealOn": {
"type": "string",
"enum": [ "enter", "observe", "snapshot" ],
"enum": [
"enter",
"observe",
"snapshot"
],
"description": "'enter', 'observe', or 'snapshot' what needs to be done to the volume to unlock the facts"
},
"reveals": {
@ -648,7 +661,7 @@
"description": "The ID of the entry this location is for"
},
"cloaked": {
"type": "bool",
"type": "boolean",
"description": "Whether this entry location is in a cloaking field",
"default": false
},
@ -679,7 +692,7 @@
"properties": {
"playerSpawnPoint": {
"$ref": "#/$defs/vector3",
"description" : "If you want the player to spawn on the new body, set a value for this. Press \"P\" in game with Debug mode on to have the game log the position you're looking at to find a good value for this."
"description": "If you want the player to spawn on the new body, set a value for this. Press \"P\" in game with Debug mode on to have the game log the position you're looking at to find a good value for this."
},
"shipSpawnPoint": {
"$ref": "#/$defs/vector3"
@ -687,7 +700,7 @@
"startWithSuit": {
"type": "boolean",
"default": false,
"description" : "If you spawn on a planet with no oxygen, you probably want to set this to true ;)"
"description": "If you spawn on a planet with no oxygen, you probably want to set this to true ;)"
}
}
},
@ -704,11 +717,11 @@
},
"frequency": {
"type": "string",
"description" : "The frequency ID of the signal. The built-in game values are \"Default\", \"Traveler\", \"Quantum\", \"EscapePod\", \"Statue\", \"WarpCore\", \"HideAndSeek\", and \"Radio\". You can also put a custom value."
"description": "The frequency ID of the signal. The built-in game values are \"Default\", \"Traveler\", \"Quantum\", \"EscapePod\", \"Statue\", \"WarpCore\", \"HideAndSeek\", and \"Radio\". You can also put a custom value."
},
"name": {
"type": "string",
"description" : "The unique ID of the signal."
"description": "The unique ID of the signal."
},
"audioClip": {
"type": "string",
@ -735,7 +748,7 @@
"identificationRadius": {
"type": "number",
"minimum": 0,
"description": "How close the player must get to the signal to identify it. This is when you learn it's name."
"description": "How close the player must get to the signal to identify it. This is when you learn its name."
},
"onlyAudibleToScope": {
"type": "boolean",
@ -759,7 +772,7 @@
"type": "number",
"default": 0,
"minimum": 0,
"description" : "Radius of the singularity. Note that this isn't the same as the event horizon, but includes the entire volume that has warped effects in it."
"description": "Radius of the singularity. Note that this isn't the same as the event horizon, but includes the entire volume that has warped effects in it."
},
"pairedSingularity": {
"type": "string",
@ -767,7 +780,7 @@
},
"targetStarSystem": {
"type": "string",
"description": "If you want a black hole to load a new star system scene, put it's name here. Optional."
"description": "If you want a black hole to load a new star system scene, put its name here. Optional."
},
"type": {
"type": "string",
@ -910,7 +923,7 @@
"default": 1
},
"invisibleWhenHidden": {
"type": "bool",
"type": "boolean",
"description": "Hide the planet completely if unexplored instead of showing an outline.",
"default": false
},
@ -953,7 +966,7 @@
},
"scale": {
"$ref": "#/$defs/vector2",
"description": "The amount to scale the x and y axis of the detail by."
"description": "The amount to scale the x and y-axis of the detail by."
}
}
}

View File

@ -95,7 +95,7 @@
<xs:element name="Entry" type="Entry" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Child entires within this entry
Child entries within this entry
</xs:documentation>
</xs:annotation>
</xs:element>

View File

@ -14,7 +14,7 @@
},
"factRequiredForWarp": {
"type": "string",
"description": "Set to the FactID that must be revealed before it can be warped to. Don't set \"CanEnterViaWarpDrive\" to false if you're using this, that would make no sense."
"description": "Set to the FactID that must be revealed before it can be warped to. Don't set `CanEnterViaWarpDrive` to false if you're using this, that would make no sense."
}
}
}

View File

@ -1,7 +1,7 @@
![new horizons thumbnail 2](https://user-images.githubusercontent.com/22628069/154112130-b777f618-245f-44c9-9408-e11141fc5fde.png)
[![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dxen_42%26type%3Dpatrons&style=flat)](https://patreon.com/xen_42)
[![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Downh%26type%3Dpatrons&style=flat)](https://patreon.com/ownh)
[![Donate](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://www.paypal.com/paypalme/xen42)
![Current version](https://img.shields.io/github/manifest-json/v/xen-42/outer-wilds-new-horizons?color=gree&filename=NewHorizons%2Fmanifest.json)
![Downloads](https://img.shields.io/github/downloads/xen-42/outer-wilds-new-horizons/total)
@ -23,6 +23,7 @@ Check the ship's log for how to use your warp drive to travel between star syste
- [Incompatible mods](#incompatible-mods)
- [Roadmap](#roadmap)
- [Development](#development)
- [Contact](#contact)
- [Credits](#credits)
@ -37,8 +38,8 @@ Check the ship's log for how to use your warp drive to travel between star syste
- Use our [template Unity project](https://github.com/xen-42/outer-wilds-unity-template) to create assets for use in NH, including all game scripts recovered using UtinyRipper
- Separate solar system scenes accessible via wormhole OR via the ship's new warp drive feature accessible via the ship's log
- Remove existing planets
- Create basic planets from heightmaps/texturemaps
- Stars, comets, asteroid belts, satellites, geysers, cloak fields
- Create planets from heightmaps/texturemaps
- Create stars, comets, asteroid belts, satellites, geysers, cloak fields
- Binary orbits
- Signalscope signals and custom frequencies
- Surface scatter: rocks, trees, etc, using in-game models, or custom ones
@ -60,16 +61,21 @@ Check the ship's log for how to use your warp drive to travel between star syste
- Implement custom Nomai scrolls
- Implement custom translatable writing
## Development
If you want to help (please dear god help us) then check out the [contact](#contact) info below.
The Unity project we use to make asset bundles for this mod is [here](https://github.com/xen-42/new-horizons-unity).
## Contact
Join the [Outer Wilds Modding Discord](https://discord.gg/MvbCbBz6Q6) if you have any questions or just want to chat about modding! Theres a New Horizons category there dedicated to discussion of this mod.
## Credits
Main authors:
- xen (New Horizons v0.1.0 onwards)
- [Bwc9876](https://github.com/Bwc9876) (New Horizons v0.9.0 onwards)
- [Mister_Nebula](https://github.com/misternebula) ([Marshmallow](https://github.com/misternebula/Marshmallow) v0.1 to v1.1.0)
New Horizons was made with help from:
- [Bwc9876](https://github.com/Bwc9876): Set up ship log entries and QOL debug options in v0.9.x, and set up the website.
- [Nageld](https://github.com/Nageld): Set up xml reading for custom dialogue in v0.8.0
- [jtsalomo](https://github.com/jtsalomo): Implemented [OW_CommonResources](https://github.com/PacificEngine/OW_CommonResources) support introduced in v0.5.0
- [Raicuparta](https://github.com/Raicuparta): Integrated the [New Horizons Template](https://github.com/xen-42/ow-new-horizons-config-template) into the Outer Wilds Mods website

View File

@ -4,16 +4,9 @@ verify_ssl = true
name = "pypi"
[packages]
jinja2 = "*"
json-schema-for-humans = "*"
markdown = "*"
htmlmin = "*"
xmlschema = "*"
rcssmin = "*"
rjsmin = "*"
pillow = "*"
[dev-packages]
menagerie-docs = "*"
[requires]
python_version = "3.10"

322
docs/Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "249c505e3423814361cd7e54a630b8d501e3fa299d2b225696522d175c85ca3a"
"sha256": "1d9327d16bbc79bdbb466d6264ad8f196504950e741eadaa1fd3f90bada696c2"
},
"pipfile-spec": 6,
"requires": {
@ -15,7 +15,24 @@
}
]
},
"default": {
"default": {},
"develop": {
"attrs": {
"hashes": [
"sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4",
"sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==21.4.0"
},
"beautifulsoup4": {
"hashes": [
"sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30",
"sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"
],
"markers": "python_version >= '3.6'",
"version": "==4.11.1"
},
"certifi": {
"hashes": [
"sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
@ -33,11 +50,11 @@
},
"click": {
"hashes": [
"sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1",
"sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"
"sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e",
"sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"
],
"markers": "python_version >= '3.6'",
"version": "==8.0.4"
"markers": "python_version >= '3.7'",
"version": "==8.1.2"
},
"colorama": {
"hashes": [
@ -49,11 +66,11 @@
},
"dataclasses-json": {
"hashes": [
"sha256:1d7f3a284a49d350ddbabde0e7d0c5ffa34a144aaf1bcb5b9f2c87673ff0c76e",
"sha256:1f60be3405dee30b86ffbf6a436db8ba5efaeeb676bfda358e516a97aa7dfce4"
"sha256:bc285b5f892094c3a53d558858a88553dd6a61a11ab1a8128a0e554385dcc5dd",
"sha256:c2c11bc8214fbf709ffc369d11446ff6945254a7f09128154a7620613d8fda90"
],
"markers": "python_version >= '3.6'",
"version": "==0.5.6"
"version": "==0.5.7"
},
"elementpath": {
"hashes": [
@ -67,7 +84,6 @@
"hashes": [
"sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178"
],
"index": "pypi",
"version": "==0.1.12"
},
"idna": {
@ -80,26 +96,41 @@
},
"jinja2": {
"hashes": [
"sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8",
"sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"
"sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119",
"sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9"
],
"index": "pypi",
"version": "==3.0.3"
"markers": "python_version >= '3.7'",
"version": "==3.1.1"
},
"json-minify": {
"hashes": [
"sha256:268e6966c0f1dcb32ac54e1d047b83deba9ce711c0763ceba63f26d3aeedf656",
"sha256:499717626144a533d64ed4a1513976cf2212958b6806a66e07dd8e22207df559"
],
"version": "==0.3.0"
},
"json-schema-for-humans": {
"hashes": [
"sha256:2272e053e7b44961c79d22628eca9c475bd3984b99401a4184ae8f4224df296a",
"sha256:986158ae543d6aae5df6bb1dbc9e23f45a374fd7e9da5165ddcd9a7596b877e7"
"sha256:66784a3d37c8f730588524cc8f103448847533f067ba8b5d76e7667675ee31f1",
"sha256:ed900db6b19b41bf681513c48ae5e403632878745775ddfc8d5b73438d2930fe"
],
"index": "pypi",
"version": "==0.40"
"markers": "python_version >= '3.7' and python_version < '4'",
"version": "==0.40.2"
},
"jsonschema": {
"hashes": [
"sha256:636694eb41b3535ed608fe04129f26542b59ed99808b4f688aa32dcf55317a83",
"sha256:77281a1f71684953ee8b3d488371b162419767973789272434bbc3f29d9c8823"
],
"markers": "python_version >= '3.7'",
"version": "==4.4.0"
},
"markdown": {
"hashes": [
"sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006",
"sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"
],
"index": "pypi",
"markers": "python_version >= '3.6'",
"version": "==3.3.6"
},
"markdown2": {
@ -112,57 +143,57 @@
},
"markupsafe": {
"hashes": [
"sha256:023af8c54fe63530545f70dd2a2a7eed18d07a9a77b94e8bf1e2ff7f252db9a3",
"sha256:09c86c9643cceb1d87ca08cdc30160d1b7ab49a8a21564868921959bd16441b8",
"sha256:142119fb14a1ef6d758912b25c4e803c3ff66920635c44078666fe7cc3f8f759",
"sha256:1d1fb9b2eec3c9714dd936860850300b51dbaa37404209c8d4cb66547884b7ed",
"sha256:204730fd5fe2fe3b1e9ccadb2bd18ba8712b111dcabce185af0b3b5285a7c989",
"sha256:24c3be29abb6b34052fd26fc7a8e0a49b1ee9d282e3665e8ad09a0a68faee5b3",
"sha256:290b02bab3c9e216da57c1d11d2ba73a9f73a614bbdcc027d299a60cdfabb11a",
"sha256:3028252424c72b2602a323f70fbf50aa80a5d3aa616ea6add4ba21ae9cc9da4c",
"sha256:30c653fde75a6e5eb814d2a0a89378f83d1d3f502ab710904ee585c38888816c",
"sha256:3cace1837bc84e63b3fd2dfce37f08f8c18aeb81ef5cf6bb9b51f625cb4e6cd8",
"sha256:4056f752015dfa9828dce3140dbadd543b555afb3252507348c493def166d454",
"sha256:454ffc1cbb75227d15667c09f164a0099159da0c1f3d2636aa648f12675491ad",
"sha256:598b65d74615c021423bd45c2bc5e9b59539c875a9bdb7e5f2a6b92dfcfc268d",
"sha256:599941da468f2cf22bf90a84f6e2a65524e87be2fce844f96f2dd9a6c9d1e635",
"sha256:5ddea4c352a488b5e1069069f2f501006b1a4362cb906bee9a193ef1245a7a61",
"sha256:62c0285e91414f5c8f621a17b69fc0088394ccdaa961ef469e833dbff64bd5ea",
"sha256:679cbb78914ab212c49c67ba2c7396dc599a8479de51b9a87b174700abd9ea49",
"sha256:6e104c0c2b4cd765b4e83909cde7ec61a1e313f8a75775897db321450e928cce",
"sha256:736895a020e31b428b3382a7887bfea96102c529530299f426bf2e636aacec9e",
"sha256:75bb36f134883fdbe13d8e63b8675f5f12b80bb6627f7714c7d6c5becf22719f",
"sha256:7d2f5d97fcbd004c03df8d8fe2b973fe2b14e7bfeb2cfa012eaa8759ce9a762f",
"sha256:80beaf63ddfbc64a0452b841d8036ca0611e049650e20afcb882f5d3c266d65f",
"sha256:84ad5e29bf8bab3ad70fd707d3c05524862bddc54dc040982b0dbcff36481de7",
"sha256:8da5924cb1f9064589767b0f3fc39d03e3d0fb5aa29e0cb21d43106519bd624a",
"sha256:961eb86e5be7d0973789f30ebcf6caab60b844203f4396ece27310295a6082c7",
"sha256:96de1932237abe0a13ba68b63e94113678c379dca45afa040a17b6e1ad7ed076",
"sha256:a0a0abef2ca47b33fb615b491ce31b055ef2430de52c5b3fb19a4042dbc5cadb",
"sha256:b2a5a856019d2833c56a3dcac1b80fe795c95f401818ea963594b345929dffa7",
"sha256:b8811d48078d1cf2a6863dafb896e68406c5f513048451cd2ded0473133473c7",
"sha256:c532d5ab79be0199fa2658e24a02fce8542df196e60665dd322409a03db6a52c",
"sha256:d3b64c65328cb4cd252c94f83e66e3d7acf8891e60ebf588d7b493a55a1dbf26",
"sha256:d4e702eea4a2903441f2735799d217f4ac1b55f7d8ad96ab7d4e25417cb0827c",
"sha256:d5653619b3eb5cbd35bfba3c12d575db2a74d15e0e1c08bf1db788069d410ce8",
"sha256:d66624f04de4af8bbf1c7f21cc06649c1c69a7f84109179add573ce35e46d448",
"sha256:e67ec74fada3841b8c5f4c4f197bea916025cb9aa3fe5abf7d52b655d042f956",
"sha256:e6f7f3f41faffaea6596da86ecc2389672fa949bd035251eab26dc6697451d05",
"sha256:f02cf7221d5cd915d7fa58ab64f7ee6dd0f6cddbb48683debf5d04ae9b1c2cc1",
"sha256:f0eddfcabd6936558ec020130f932d479930581171368fd728efcfb6ef0dd357",
"sha256:fabbe18087c3d33c5824cb145ffca52eccd053061df1d79d4b66dafa5ad2a5ea",
"sha256:fc3150f85e2dbcf99e65238c842d1cfe69d3e7649b19864c1cc043213d9cd730"
"sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003",
"sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88",
"sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5",
"sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7",
"sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a",
"sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603",
"sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1",
"sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135",
"sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247",
"sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6",
"sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601",
"sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77",
"sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02",
"sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e",
"sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63",
"sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f",
"sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980",
"sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b",
"sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812",
"sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff",
"sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96",
"sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1",
"sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925",
"sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a",
"sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6",
"sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e",
"sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f",
"sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4",
"sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f",
"sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3",
"sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c",
"sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a",
"sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417",
"sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a",
"sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a",
"sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37",
"sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452",
"sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933",
"sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a",
"sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"
],
"markers": "python_version >= '3.7'",
"version": "==2.1.0"
"version": "==2.1.1"
},
"marshmallow": {
"hashes": [
"sha256:04438610bc6dadbdddb22a4a55bcc7f6f8099e69580b2e67f5a681933a1f4400",
"sha256:4c05c1684e0e97fe779c62b91878f173b937fe097b356cd82f793464f5bc6138"
"sha256:2aaaab4f01ef4f5a011a21319af9fce17ab13bf28a026d1252adab0e035648d5",
"sha256:ff79885ed43b579782f48c251d262e062bce49c65c52412458769a4fb57ac30f"
],
"markers": "python_version >= '3.6'",
"version": "==3.14.1"
"markers": "python_version >= '3.7'",
"version": "==3.15.0"
},
"marshmallow-enum": {
"hashes": [
@ -171,6 +202,14 @@
],
"version": "==1.5.1"
},
"menagerie-docs": {
"hashes": [
"sha256:86474264ca3f3aa289bf22e4f2b0287ba29c946bd54e34a1f6c77d549c3c23ad",
"sha256:adee872cde3616c2bab6b8e4ad15f3aac95dbc9340ff02377a21d257ec5fa108"
],
"index": "pypi",
"version": "==0.0.5"
},
"mypy-extensions": {
"hashes": [
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
@ -178,46 +217,65 @@
],
"version": "==0.4.3"
},
"ndicts": {
"hashes": [
"sha256:5053fc5ca7b8a281081274702ebf1584e341f40a68e6ab8f6b4b79f4b3fdf18e",
"sha256:8e8226f15c0b25565aa391797963b78c95930e12efc40e905153130783e766be"
],
"markers": "python_version >= '3.8' and python_version < '4'",
"version": "==0.1.0"
},
"packaging": {
"hashes": [
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
],
"markers": "python_version >= '3.6'",
"version": "==21.3"
},
"pillow": {
"hashes": [
"sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97",
"sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049",
"sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c",
"sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae",
"sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28",
"sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030",
"sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56",
"sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976",
"sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e",
"sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e",
"sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f",
"sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b",
"sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a",
"sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e",
"sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa",
"sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7",
"sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00",
"sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838",
"sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360",
"sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b",
"sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a",
"sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd",
"sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4",
"sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70",
"sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204",
"sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc",
"sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b",
"sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669",
"sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7",
"sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e",
"sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c",
"sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092",
"sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c",
"sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5",
"sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"
"sha256:01ce45deec9df310cbbee11104bae1a2a43308dd9c317f99235b6d3080ddd66e",
"sha256:0c51cb9edac8a5abd069fd0758ac0a8bfe52c261ee0e330f363548aca6893595",
"sha256:17869489de2fce6c36690a0c721bd3db176194af5f39249c1ac56d0bb0fcc512",
"sha256:21dee8466b42912335151d24c1665fcf44dc2ee47e021d233a40c3ca5adae59c",
"sha256:25023a6209a4d7c42154073144608c9a71d3512b648a2f5d4465182cb93d3477",
"sha256:255c9d69754a4c90b0ee484967fc8818c7ff8311c6dddcc43a4340e10cd1636a",
"sha256:35be4a9f65441d9982240e6966c1eaa1c654c4e5e931eaf580130409e31804d4",
"sha256:3f42364485bfdab19c1373b5cd62f7c5ab7cc052e19644862ec8f15bb8af289e",
"sha256:3fddcdb619ba04491e8f771636583a7cc5a5051cd193ff1aa1ee8616d2a692c5",
"sha256:463acf531f5d0925ca55904fa668bb3461c3ef6bc779e1d6d8a488092bdee378",
"sha256:4fe29a070de394e449fd88ebe1624d1e2d7ddeed4c12e0b31624561b58948d9a",
"sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652",
"sha256:5a3ecc026ea0e14d0ad7cd990ea7f48bfcb3eb4271034657dc9d06933c6629a7",
"sha256:5cfca31ab4c13552a0f354c87fbd7f162a4fafd25e6b521bba93a57fe6a3700a",
"sha256:66822d01e82506a19407d1afc104c3fcea3b81d5eb11485e593ad6b8492f995a",
"sha256:69e5ddc609230d4408277af135c5b5c8fe7a54b2bdb8ad7c5100b86b3aab04c6",
"sha256:6b6d4050b208c8ff886fd3db6690bf04f9a48749d78b41b7a5bf24c236ab0165",
"sha256:7a053bd4d65a3294b153bdd7724dce864a1d548416a5ef61f6d03bf149205160",
"sha256:82283af99c1c3a5ba1da44c67296d5aad19f11c535b551a5ae55328a317ce331",
"sha256:8782189c796eff29dbb37dd87afa4ad4d40fc90b2742704f94812851b725964b",
"sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458",
"sha256:97bda660702a856c2c9e12ec26fc6d187631ddfd896ff685814ab21ef0597033",
"sha256:a325ac71914c5c043fa50441b36606e64a10cd262de12f7a179620f579752ff8",
"sha256:a336a4f74baf67e26f3acc4d61c913e378e931817cd1e2ef4dfb79d3e051b481",
"sha256:a598d8830f6ef5501002ae85c7dbfcd9c27cc4efc02a1989369303ba85573e58",
"sha256:a5eaf3b42df2bcda61c53a742ee2c6e63f777d0e085bbc6b2ab7ed57deb13db7",
"sha256:aea7ce61328e15943d7b9eaca87e81f7c62ff90f669116f857262e9da4057ba3",
"sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea",
"sha256:c24f718f9dd73bb2b31a6201e6db5ea4a61fdd1d1c200f43ee585fc6dcd21b34",
"sha256:c5b0ff59785d93b3437c3703e3c64c178aabada51dea2a7f2c5eccf1bcf565a3",
"sha256:c7110ec1701b0bf8df569a7592a196c9d07c764a0a74f65471ea56816f10e2c8",
"sha256:c870193cce4b76713a2b29be5d8327c8ccbe0d4a49bc22968aa1e680930f5581",
"sha256:c9efef876c21788366ea1f50ecb39d5d6f65febe25ad1d4c0b8dff98843ac244",
"sha256:de344bcf6e2463bb25179d74d6e7989e375f906bcec8cb86edb8b12acbc7dfef",
"sha256:eb1b89b11256b5b6cad5e7593f9061ac4624f7651f7a8eb4dfa37caa1dfaa4d0",
"sha256:ed742214068efa95e9844c2d9129e209ed63f61baa4d54dbf4cf8b5e2d30ccf2",
"sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97",
"sha256:fb89397013cf302f282f0fc998bb7abf11d49dcff72c8ecb320f76ea6e2c5717"
],
"index": "pypi",
"version": "==9.0.1"
"markers": "python_version >= '3.7'",
"version": "==9.1.0"
},
"pygments": {
"hashes": [
@ -227,6 +285,41 @@
"markers": "python_version >= '3.5'",
"version": "==2.11.2"
},
"pyparsing": {
"hashes": [
"sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954",
"sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"
],
"markers": "python_full_version >= '3.6.8'",
"version": "==3.0.8"
},
"pyrsistent": {
"hashes": [
"sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c",
"sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc",
"sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e",
"sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26",
"sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec",
"sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286",
"sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045",
"sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec",
"sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8",
"sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c",
"sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca",
"sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22",
"sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a",
"sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96",
"sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc",
"sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1",
"sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07",
"sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6",
"sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b",
"sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5",
"sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"
],
"markers": "python_version >= '3.7'",
"version": "==0.18.1"
},
"pytz": {
"hashes": [
"sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c",
@ -296,7 +389,6 @@
"sha256:f1a37bbd36b050813673e62ae6464467548628690bf4d48a938170e121e8616e",
"sha256:f31c82d06ba2dbf33c20db9550157e80bb0c4cbd24575c098f0831d1d2e3c5df"
],
"index": "pypi",
"version": "==1.1.0"
},
"requests": {
@ -330,9 +422,16 @@
"sha256:d63e193a2f932a786ae82068aa76d1d126fcdff8582094caff9e5e66c4dcc124",
"sha256:e18fe1a610fb105273bb369f61c2b0bd9e66a3f0792e27e4cac44e42ace1968b"
],
"index": "pypi",
"version": "==1.2.0"
},
"soupsieve": {
"hashes": [
"sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759",
"sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"
],
"markers": "python_version >= '3.6'",
"version": "==2.3.2.post1"
},
"typing-extensions": {
"hashes": [
"sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
@ -351,20 +450,19 @@
},
"urllib3": {
"hashes": [
"sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed",
"sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.8"
"version": "==1.26.9"
},
"xmlschema": {
"hashes": [
"sha256:3ce6fe408a8c0a0ca5917cbe6181a933dfb5cfade9714eeb07b6335f9aff7b10",
"sha256:a7ba52b774a87b59c6428cd9e3601210cbb226552208015bd40800698a6500ad"
"sha256:be1eedce6a4b911fd3a7f4060d0811951820a13410e61f0454b30e9f4e7cf197",
"sha256:dbd68bded2fef00c19cf37110ca0565eca34cf0b6c9e1d3b62ad0de8cbb582ca"
],
"index": "pypi",
"version": "==1.9.2"
"markers": "python_version >= '3.7'",
"version": "==1.10.0"
}
},
"develop": {}
}
}

View File

@ -17,28 +17,24 @@ pip install --user pipenv
```
Install dependencies
```shell
pipenv install
pipenv install --dev
```
## Environment Variables
- OUT_DIR: Path to put before all links and static files, see below for recommended values
- URL_PREFIX: Path to put before all links and static files, see below for recommended values
- Production: "/"
- Local Build: "" (set as empty string)
- PyCharm Development Server: "/outer-wilds-new-horizons/docs/out/"
- BASE_URL: Base url of the website we're hosting on
- Local: Leave blank
- Local (but wanting to test open-graph/twitter): "https://nh.outerwildsmods.com/"
- Production: "https://nh.outerwildsmods.com/"
## Copy Schemas
Create a folder called `schemas` in the content folder and copy all schemas to generate into it, make sure not to add this folder to git.
Create a folder called `schemas` in the `docs/content/pages/` folder and copy all schemas to generate into it, make sure not to add this folder to git.
Production build automatically copies over schemas.
## Generating
Run `generate.py` with pipenv
Run `generate` with pipenv
```shell
pipenv run python generate.py
pipenv run python -m menagerie generate
```
## Opening

56
docs/config.json Normal file
View File

@ -0,0 +1,56 @@
{
"$schema": "https://raw.githubusercontent.com/Bwc9876/menagerie/master/menagerie/config_schema.json",
"cache_enabled": false,
"base_url": "https://nh.outerwildsmods.com/",
"themes": {
"bootstrap": "https://bootswatch.com/5/darkly/bootstrap.min.css",
"highlight_js": "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/styles/github-dark-dimmed.min.css",
"navbar_color": "dark"
},
"styles": {
"base": "styles/base.css",
"schema": "styles/schema.css"
},
"brand": {
"app_name": "New Horizons",
"favicon_folder": "fav/",
"navbar_icon": "images/icon.webp",
"navbar_icon_size": [29, 29],
"socials": [
{
"name": "Discord",
"link": "https://discord.gg/wusTQYbYTc",
"icon": "discord"
},
{
"name": "GitHub",
"link": "https://github.com/xen-42/outer-wilds-new-horizons",
"icon": "github"
},
{
"name": "Patreon",
"link": "https://patreon.com/ownh",
"icon": "coin"
}
],
"meta": {
"description": "Documentation on how to use the New Horizons planet creation tool for Outer Wilds.",
"keywords": ["New Horizons", "Outer Wilds", "Modding", "C#", "Unity"],
"categories": ["games", "utilities"],
"image": "images/home/home_logo.webp",
"image_alt": "The New Horizons Logo",
"theme_color": "#ffab8a",
"bg_color": "#1a1a1a"
},
"footer": {
"show_made_with": false,
"links": [
{
"link": "https://github.com/xen-42/outer-wilds-new-horizons/issues/new/choose",
"text": "Report an issue",
"external": true
}
]
}
}
}

View File

@ -1,80 +0,0 @@
{% from 'base/macros.jinja2' import external_link, is_active_page, nav_item, defer_css with context %}
<!DOCTYPE html>
<html lang="en">
<head>
{% include "base/meta.jinja2" %}
<link href="https://bootswatch.com/5/darkly/bootstrap.min.css"
crossorigin="anonymous" rel="stylesheet">
{{ defer_css("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css") }}
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
<script crossorigin="anonymous" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<link rel="stylesheet" href="{{ 'styles/base.min.css'|static }}"/>
{% block resources %} {% endblock %}
</head>
<body class="vh-100 d-flex flex-column" style="overflow-x: hidden;" id="top" onload="{% block onLoad %}{% endblock %}" {% if page.render_toc %}data-bs-spy="scroll" data-bs-target="#TableOfContents" data-bs-offset="65"{% endif %}>
<header>
<nav class="navbar navbar-expand-xl navbar-dark bg-dark sticky-top mb-3">
<div class="container-fluid">
<a class="navbar-brand" href="{{ 'home'|route }}" aria-label="Home">
<img width="29" height="29" src="{{ "images/icon.webp"|static }}" alt="New Horizons Logo"
class="d-inline-block align-text-top me-2"/>
New Horizons</a>
<button class="navbar-toggler align-text-middle" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarMain" aria-controls="navbarMain"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarMain">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{% for nav_page in pages %}
{{ nav_item(nav_page.title, nav_page.title|route) }}
{% endfor %}
<li class="nav-item dropdown">
<a class="nav-link {% if page in schemas %}active{% endif %} dropdown-toggle" {% if page in schemas %}aria-current="page"{% endif %} href="#" id="navbarDropdown" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
Schemas
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
{% for schema in schemas %}
<li><a class="dropdown-item"
href="{{ schema.title|route }}">{{ schema.title|title }}</a></li>
{% endfor %}
</ul>
</li>
</ul>
<hr class="d-xl-none"/>
<ul class="navbar-nav mb-2 ms-md-auto mb-lg-0">
<li class="nav-item me-2">
{{ external_link("<i class=\"bi-github\"></i><small class=\"d-xl-none ms-2\">GitHub</small>", "https://github.com/xen-42/outer-wilds-new-horizons", "nav-link p-2 fs-5") }}
</li>
<li class="nav-item me-2">
{{ external_link("<i class=\"bi-discord\"></i><small class=\"d-xl-none ms-2\">Discord</small>", "https://discord.gg/9vE5aHxcF9", "nav-link p-2 fs-5") }}
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container-lg flex-grow-1">
<main class="main">
<div>
{% block content %} {% endblock %}
</div>
</main>
</div>
<footer class="container-fluid w-100 mt-5 pt-4 pb-3 bg-dark">
<div class="row gy-3 text-center">
<div class="col-md">
<p class="p-0 m-0">Last Generated: {{ ''|gen_time }}</p>
</div>
<div class="col-md">
<a class="link-light" href="#top">Back To Top</a>
</div>
<div class="col-md">
{{ external_link('Report An Issue', "https://github.com/xen-42/outer-wilds-new-horizons/issues/new/choose", 'link-light') }}
</div>
</div>
</footer>
</body>
</html>

View File

@ -1,12 +0,0 @@
{% macro external_link(display_name, link, class) %}<a class="{{ class|default("") }}" target="_blank" rel="noopener" href="{{ link }}">{{ display_name|safe }}</a>{% endmacro %}
{% macro is_active_page(title) %}{% if title == page.title %}active{% endif %}{% endmacro %}
{% macro nav_item(title, href) %}<li class="nav-item me-1"><a href="{{ href }}" class="nav-link {% if title|lower == page.title|lower %}active{% endif %}" {% if title|lower == page.title|lower %}aria-current="page"{% endif %}>{{ title }}</a></li>{% endmacro %}
{% macro badge(type, content, classes) %}<span class="badge rounded-pill bg-{{ type }} {{ classes }}">{{ content|safe }}</span>{% endmacro %}
{% macro defer_css(link) %}
<link rel="preload" href="{{ link }}" as="style" onload="this.onload=null;this.rel='stylesheet';"/>
<noscript><link rel="stylesheet" href="{{ link }}"/></noscript>
{% endmacro %}

View File

@ -1,63 +0,0 @@
{# Macros #}
{% macro og(name, content) %}<meta property="og:{{ name }}" content="{{ content }}"/>{% endmacro %}
{% macro tw(name, content) %}<meta name="twitter:{{ name }}" content="{{ content }}"/>{% endmacro %}
{% macro fav(filename) %}{{ ("fav/" + filename)|static }}{% endmacro %}
{# Variable Declarations #}
{% if page.title|lower == 'home' %}
{% set title="New Horizons Documentation" %}
{% else %}
{% set title=page.title + " - New Horizons Documentation" %}
{% endif %}
{% set desc="Documentation for creating planets with the New Horizons mod for Outer Wilds" %}
{% if page.description %}
{% set desc=page.description %}
{% endif %}
{% set img="images/home/home_logo.webp"|static|full_url %}
{% set canonical=page.title|route|full_url %}
{% set theme_color="#222222" %}
{# Meta Info #}
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{{ title }}</title>
<meta name="keywords" content="New Horizons, Outer Wilds, Modding, C#, Unity" />
<meta name="description" content="{{ desc }}"/>
<link rel="canonical" href="{{ canonical }}">
{# OpenGraph Info #}
{{ og("type", "website") }}
{{ og("title", title) }}
{{ og("description", desc) }}
{{ og("url", canonical) }}
{{ og("image", img) }}
{{ og("image:alt", "The New Horizons Logo") }}
{# Twitter Info #}
{{ tw("title", title) }}
{{ tw("description", desc) }}
{{ tw("card", "summary_large_image") }}
{{ tw("image", img) }}
{# Favicons #}
<link rel="apple-touch-icon" sizes="57x57" href="{{ fav('apple-icon-57x57.png') }}">
<link rel="apple-touch-icon" sizes="60x60" href="{{ fav('apple-icon-60x60.png') }}">
<link rel="apple-touch-icon" sizes="72x72" href="{{ fav('apple-icon-72x72.png') }}">
<link rel="apple-touch-icon" sizes="76x76" href="{{ fav('apple-icon-76x76.png') }}">
<link rel="apple-touch-icon" sizes="114x114" href="{{ fav("apple-icon-114x114.png") }}">
<link rel="apple-touch-icon" sizes="120x120" href="{{ fav("apple-icon-120x120.png") }}">
<link rel="apple-touch-icon" sizes="144x144" href="{{ fav("apple-icon-144x144.png") }}">
<link rel="apple-touch-icon" sizes="152x152" href="{{ fav("apple-icon-152x152.png") }}">
<link rel="apple-touch-icon" sizes="180x180" href="{{ fav("apple-icon-180x180.png") }}">
<link rel="icon" type="image/png" sizes="192x192" href="{{ fav("android-icon-192x192.png") }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ fav("favicon-32x32.png") }}">
<link rel="icon" type="image/png" sizes="96x96" href="{{ fav("favicon-96x96.png") }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ fav("favicon-16x16.png") }}">
<link rel="manifest" href="{{ "fav/manifest.webmanifest"|static }}">
<meta name="msapplication-config" content="{{ "fav/browserconfig.xml"|static }}" />
<meta name="msapplication-TileColor" content="{{ theme_color }}">
<meta name="msapplication-TileImage" content="{{ fav("ms-icon-144x144.png") }}">
<meta name="theme-color" data-react-helmet="true" content="{{ theme_color }}">

View File

@ -1,46 +0,0 @@
{% extends "base/base.jinja2" %}
{% from "base/macros.jinja2" import defer_css %}
{% set br="lg" %}
{% set col_num=3 %}
{% block resources %}
{{ defer_css("https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/styles/github-dark-dimmed.min.css") }}
<script onload="hljs.highlightAll();" defer
src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/highlight.min.js"></script>
{% endblock %}
{% block content %}
<div class="row g-6">
{% if page.render_toc %}
<div class="col-{{ br }}-{{ col_num }}">
<nav id="TableOfContents"
class="navbar navbar-light sticky-top flex-column align-items-stretch p-3"
style="max-height: 100vh !important;overflow-x: hidden;overflow-y: auto;">
{% macro render(item) %}
<a id="{{ item['id'] }}-toc" class="nav-link toc-link px-1 mb-1" href="#{{ item['id'] }}"
style="margin-left: {{ 0.7 * item['level'] }}rem;">{{ item['name'] }}</a>
{% if item['children'] %}
<nav class="nav nav-pills flex-column">
{% for child in item['children'] %}
{{ render(child) }}
{% endfor %}
</nav>
{% endif %}
{% endmacro %}
<nav class="nav nav-pills flex-column">
<strong class="nav-text pb-2">On This Page</strong>
{% for item in page.table_of_contents %}
{{ render(item) }}
{% endfor %}
</nav>
</nav>
</div>
<hr class="d-{{ br }}-none mt-3"/>
{% endif %}
<div id="page-contents" {% if page.render_toc %}class="col-{{ br }}-{{ 12 - col_num }}"{% else %}class="col"{% endif %}>
{{ rendered|safe }}
</div>
</div>
{% endblock %}

View File

@ -1,14 +0,0 @@
{% if type_name == "string" %}
{% if schema.kw_min_length %}
{{ restriction("Must be at least <code>" ~ schema.kw_min_length.literal ~ "</code> characters long", "min-length", schema.kw_min_length.html_id) }}
{% endif %}
{% if schema.kw_max_length %}
{{ restriction("Must be at most <code>" ~ schema.kw_max_length.literal ~ "</code> characters long", "max-length", schema.kw_max_length.html_id) }}
{% endif %}
{% endif %}
{% if type_name in ["integer", "number"] %}
{% set restriction_text = (schema | get_numeric_restrictions_text("<code>", "</code>")) %}
{% if restriction_text %}
{{ restriction(schema | get_numeric_restrictions_text("<code>", "</code>"), "numeric", schema.html_id ~ "_number") }}
{% endif %}
{% endif %}

View File

@ -1,13 +0,0 @@
<div class="breadcrumbs">
{% for node in schema.nodes_from_root %}
{% if loop.first %}
Root
{% else %}
<a href="#{{ node.html_id }}"
onclick="anchorLink('{{ node.html_id }}')">{{ node.name_for_breadcrumbs | upper_first }}</a>
{% endif %}
{% if not loop.last %}
<i class="bi-arrow-right-short"></i>
{% endif %}
{% endfor %}
</div>

View File

@ -1,122 +0,0 @@
{% from "base/schema/json/macro_restriction.jinja2" import restriction with context %}
{% from "base/macros.jinja2" import badge %}
{% macro tabbed_section(operator, current_node) %}
{% include "base/schema/json/tabbed_section.jinja2" %}
{% endmacro %}
{% macro content(schema, skip_headers=False) %}
{% set keys = schema.keywords %}
{# Resolve type #}
{% set type_name = schema.type_name %}
{% if not skip_headers %}
{% if config.show_breadcrumbs %}
{% include "base/schema/json/breadcrumbs.jinja2" %}
{% endif %}
{# Display type #}
{% if not schema is combining %}
<div class="row">
<div class="col">
{{ badge("secondary", "Type: " + type_name) }}
</div>
</div>
{% endif %}
{# Display default #}
{% set default_value = schema.default_value %}
{% if default_value %}
<div class="row">
<div class="col">
{{ badge("secondary", "Default: " + default_value) }}
</div>
</div>
{% endif %}
<br/>
{% set description = (schema | get_description) %}
{% include "base/schema/json/section_description.jinja2" %}
{% endif %}
{% if schema.should_be_a_link(config) %}
<a href="#{{ schema.links_to.html_id }}" onclick="anchorLink('{{ schema.links_to.html_id }}')" class="ref-link">Same definition as {{ schema.links_to.link_name }}</a>
{% elif schema.refers_to %}
{{ content(schema.refers_to_merged, True) }}
{% else %}
{# Handle having oneOf or allOf with only one condition #}
{% if schema.kw_all_of and (schema.kw_all_of.array_items | length) == 1 %}
{{ content(schema.kw_all_of.array_items[0]) }}
{% elif schema.kw_any_of and (schema.kw_any_of.array_items | length) == 1 %}
{{ content(schema.kw_any_of.array_items[0]) }}
{% else %}
{% if schema.explicit_no_additional_properties %}
{{ badge("info", "No Additional Properties") }}
{% endif %}
{# Combining: allOf, anyOf, oneOf, not #}
{% if schema.kw_all_of %}
<div class="all-of-value" id="{{ schema.kw_all_of.html_id }}">{{ tabbed_section("allOf", schema.kw_all_of) }}</div>
{% endif %}
{% if schema.kw_any_of %}
<div class="any-of-value" id="{{ schema.kw_any_of.html_id }}">{{ tabbed_section("anyOf", schema.kw_any_of) }}</div>
{% endif %}
{% if schema.kw_one_of %}
<div class="one-of-value" id="{{ schema.kw_one_of.html_id }}">{{ tabbed_section("oneOf", schema.kw_one_of) }}</div>
{% endif %}
{% if schema.kw_not %}
{% include "base/schema/json/section_not.jinja2" %}
{% endif %}
{# Enum and const #}
{% if schema.kw_enum %}
<div class="enum-value" id="{{ schema.kw_enum.html_id }}">
<h4>Must be one of:</h4>
<ul class="list-group">
{% for enum_choice in schema.kw_enum.array_items %}
<li class="list-group-item enum-item">{{ enum_choice.literal | python_to_json }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if schema.kw_const %}
<span class="const-value" id="{{ schema.kw_const.html_id }}">Specific value: <code>{{ schema.kw_const.raw | python_to_json }}</code></span>
{% endif %}
{# Pattern (Regular Expression) #}
{% if schema.kw_pattern %}
<span class="pattern-value" id="{{ schema.kw_pattern.html_id }}">Must match regular expression: <code>{{ schema.kw_pattern.literal | escape }}</code></span>
{% endif %}
{# Conditional subschema, or if-then-else section #}
{% if schema.has_conditional %}
{% include "base/schema/json/section_conditional_subschema.jinja2" %}
{% endif %}
{# Required properties that are not defined under "properties". They will only be listed #}
{% include "base/schema/json/section_undocumented_required_properties.jinja2" %}
{# Show the requested type(s) #}
{% include "base/schema/json/badge_type.jinja2" %}
{# Show array restrictions #}
{% if type_name.startswith("array") %}
{% include "base/schema/json/section_array.jinja2" %}
{% endif %}
{# Display examples #}
{% set examples = schema.examples %}
{% if examples %}
{% include "base/schema/json/section_examples.jinja2" %}
{% endif %}
{# Properties, pattern properties, additional properties #}
{% for sub_property in schema.iterate_properties %}
{% include "base/schema/json/section_properties.jinja2" %}
{% endfor %}
{% endif %}
{% endif %}
{% endmacro %}

View File

@ -1,5 +0,0 @@
{% from "base/macros.jinja2" import badge %}
{% macro restriction(inner_text, css_class_name, html_id) %}
<p>{{ badge("dark", inner_text|safe, 'p-1') }}</p>
{% endmacro %}

View File

@ -1,21 +0,0 @@
{% extends "base/base.jinja2" %}
{% from 'base/schema/json/content.jinja2' import content with context %}
{% block resources %}
{% include "base/schema/schema_includes.jinja2" %}
{% endblock %}
{% block onLoad %}anchorOnLoad();{% endblock %}
{% block content %}
<div class="row">
<div class="col text-center">
<h1>{{ title|title }}</h1>
</div>
</div>
<div class="row">
<div class="col">
{{ content(schema) }}
</div>
</div>
{% endblock %}

View File

@ -1,36 +0,0 @@
{% if schema.kw_min_items %}
{{ restriction("Must contain a minimum of <code>" ~ schema.kw_min_items.literal ~ "</code> Items", "min-items", schema.kw_min_items.html_id) }}
{% endif %}
{% if schema.kw_max_items %}
{{ restriction("Must contain a maximum of <code>" ~ schema.kw_max_items.literal ~ "</code> Items", "max-items", schema.kw_max_items.html_id) }}
{% endif %}
{% if schema.kw_unique_items and schema.kw_unique_items.literal == True %}
{{ restriction("All items must be unique", "unique-items", schema.kw_unique_items.html_id) }}
{% endif %}
{% if schema.array_items_def %}
<h4>Each item of this array must be:</h4>
<div class="card">
<div class="card-body items-definition" id="{{ schema.array_items_def.html_id }}">
{{ content(schema.array_items_def) }}
</div>
</div>
{% endif %}
{% if schema.tuple_validation_items %}
<h4>Tuple Validation</h4>
{% for item in schema.tuple_validation_items %}
<h5>Item at {{ loop.index }} must be:</h5>
<div class="card">
<div class="card-body items-definition" id="{{ item.html_id }}">
{{ content(item) }}
</div>
</div>
{% endfor %}
{% endif %}
{% if schema.kw_contains and schema.kw_contains.literal != {} %}
<h4>At least one of the items must be:</h4>
<div class="card">
<div class="card-body items-contain-definition" id="{{ schema.kw_contains.html_id }}">
{{ content(schema.kw_contains) }}
</div>
</div>
{% endif %}

View File

@ -1,58 +0,0 @@
<h2 class="handle">
<label>Conditional Sub-schema</label>
</h2>
<p>If the conditions in the "If" tab are respected, then the conditions in the "Then" tab should be respected.
Otherwise, the conditions in the "Else" tab should be respected.</p>
<ul class="nav nav-tabs" id="{{ schema.html_id }}_condition_tabs" role="tablist">
{% set tab_id = schema.kw_if.html_id %}
<li class="nav-item">
<a class="nav-link active"
id="{{ tab_id }}" data-toggle="tab" href="#tab-pane_{{ tab_id }}" role="tab"
onclick="setAnchor('#{{ tab_id }}')"
>If</a>
</li>
{% if schema.kw_then %}
{% set tab_id = schema.kw_then.html_id %}
<li class="nav-item">
<a class="nav-link"
id="{{ tab_id }}" data-toggle="tab" href="#tab-pane_{{ tab_id }}" role="tab"
onclick="setAnchor('#{{ tab_id }}')"
>Then</a>
</li>
{%- endif -%}
{%- if schema.kw_else -%}
{%- set tab_id = schema.kw_else.html_id -%}
<li class="nav-item">
<a class="nav-link"
id="{{ tab_id }}" data-toggle="tab" href="#tab-pane_{{ tab_id }}" role="tab"
onclick="setAnchor('#{{ tab_id }}')"
>Else</a>
</li>
{%- endif -%}
</ul>
<div class="tab-content card">
{% set tab_id = schema.kw_if.html_id %}
<div class="tab-pane fade card-body active show"
id="tab-pane_{{ tab_id }}" role="tabpanel">
{{ content(schema.kw_if) }}
</div>
{% if schema.kw_then %}
{% set tab_id = schema.kw_then.html_id %}
<div class="tab-pane fade card-body"
id="tab-pane_{{ tab_id }}" role="tabpanel">
{{ content(schema.kw_then) }}
</div>
{%- endif -%}
{%- if schema.kw_else -%}
{% set tab_id = schema.kw_else.html_id %}
<div class="tab-pane fade card-body"
id="tab-pane_{{ tab_id }}" role="tabpanel">
{{ content(schema.kw_else) }}
</div>
{%- endif -%}
</div>

View File

@ -1,20 +0,0 @@
{# Display description #}
{% if description %}
<div class="row">
<div class="col">
{% if not config.collapse_long_descriptions or description is description_short %}
<span class="description">{{ description }}</span>
{% else %}
<div class="description collapse" id="collapseDescription_{{ schema.html_id }}">
{{ description }}
</div>
<div>
<a class="collapse-description-link collapsed" data-toggle="collapse"
href="#collapseDescription_{{ schema.html_id }}"
aria-expanded="false" aria-controls="collapseDescription{{ schema.html_id }}"
></a>
</div>
{% endif %}
</div>
</div>
{% endif %}

View File

@ -1,18 +0,0 @@
<br/>
<div class="badge badge-secondary">Example{% if examples|length > 1 %}s{% endif %}:</div>
<br/>
{% for example in examples %}
{% set example_id = schema.html_id ~ "_ex" ~ loop.index %}
{% set example_is_long = example is not description_short %}
{% if example_is_long %}
<button class="btn btn-light example-show collapsed" data-toggle="collapse" data-target="#{{ example_id }}" aria-controls="{{ example_id }}"></button>
{% endif %}
<div id="{{ example_id }}" class="{% if example_is_long %}collapse {% endif %}jumbotron examples">
{% if not examples_as_yaml %}
{{ example | highlight_json_example | safe }}
{% else %}
{{ example | highlight_yaml_example | safe }}
{% endif %}
</div>
{% endfor %}

View File

@ -1,8 +0,0 @@
<div class="not-value">
<h4>Must <strong>not</strong> be:</h4>
<div class="card">
<div class="card-body" id="{{ card_id }}">
{{ content(schema.kw_not) }}
</div>
</div>
</div>

View File

@ -1,64 +0,0 @@
{% from "base/macros.jinja2" import badge %}
{% set html_id = sub_property.html_id %}
<div class="row my-2">
<div class="col">
<div class="accordion" id="accordion{{ html_id }}">
<div class="accordion-item">
<h2 class="accordion-header" id="heading{{ html_id }}">
<button class="accordion-button collapsed" type="button"
data-bs-toggle="collapse"
data-bs-target="#{{ html_id }}"
aria-expanded="false" aria-controls="{{ html_id }}"
onclick="setAnchor('#{{ html_id }}')">
{% if sub_property.is_additional_properties %}
<em>
{% endif %}
<span class="property-nam align-middle pb-1">{{ sub_property.property_display_name | upper_first | escape }}</span>
{% if sub_property.is_additional_properties %}
</em>
{% endif %}
{% macro subprop_badge(type, content) %}{{ badge(type, content|title, "required-property, ms-2") }}{% endmacro %}
{% if sub_property.is_required_property %}
{{ " " }}{{ subprop_badge('warning', "Required") }}
{% endif %}
{% if sub_property is deprecated %}
{{ " " }}{{ subprop_badge('danger', "Deprecated") }}
{% endif %}
{% if sub_property.is_pattern_property %}
{{ " " }}{{ subprop_badge('info', "Pattern Property") }}
{% endif %}
</button>
</h2>
<div id="{{ html_id }}"
class="accordion-collapse collapse{% if expanded %} show{% endif %}"
aria-labelledby="heading{{ html_id }}"
data-parent="#accordion{{ html_id }}">
<div class="accordion-body">
{% if sub_property.is_pattern_property %}
<h2 class="handle">
<label>Pattern Property</label>
</h2>
<p>All property whose name matches the following regular expression must respect the
following
conditions</p>
<span class="pattern-value">Property name regular expression: <code>{{ sub_property.property_name | escape }}</code></span>
<br/>
{% endif %}
{% if sub_property.is_additional_properties %}
{% if sub_property.is_additional_properties_schema %}
<p class="additional-properties">Each additional property must conform to the following
schema</p>
{% else %}
<p class="additional-properties">Additional Properties of any type are allowed.</p>
{% endif %}
{% endif %}
{{ content(sub_property) }}
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,11 +0,0 @@
{% set undocumented_required_properties = schema | get_undocumented_required_properties %}
{% if undocumented_required_properties %}
<div class="enum-value">
<h4>The following properties are required:</h4>
<ul class="list-group">
{% for required_property in undocumented_required_properties %}
<li class="list-group-item required-property">{{ required_property }}</li>
{% endfor %}
</ul>
</div>
{% endif %}

View File

@ -1,25 +0,0 @@
<h2 class="handle">
<label>{% if operator == "allOf" %}All of{% elif operator == "anyOf" %}Any of{% elif operator == "oneOf" %}One of{% endif %}</label>
</h2>
{% set tab_label = "Option" %}
{% if operator == "allOf" %}
{% set tab_label = "Requirement" %}
{% endif %}
<ul class="nav nav-tabs" id="tabs{{ current_node.html_id }}_{{ operator }}" role="tablist">
{% for node in current_node.array_items %}
<li class="nav-item">
<a class="nav-link {% if loop.index == 1 %}active {% endif %} {{ operator }}-option"
id="{{ node.html_id }}" data-toggle="tab" href="#tab-pane_{{ node.html_id }}" role="tab"
onclick="setAnchor('#{{ node.html_id }}')"
>{{ node.definition_name or tab_label ~ " " ~ loop.index }}</a>
</li>
{% endfor %}
</ul>
<div class="tab-content card">
{% for node in current_node.array_items %}
<div class="tab-pane fade card-body {% if loop.index == 1 %}active show{% endif %}"
id="tab-pane_{{ node.html_id }}" role="tabpanel">
{{ content(node) }}
</div>
{% endfor %}
</div>

View File

@ -1,2 +0,0 @@
<script defer src="{{ 'scripts/schema.min.js'|static }}"></script>
<link rel="stylesheet" href="{{ 'styles/schema.min.css'|static }}"/>

View File

@ -1,99 +0,0 @@
{% extends "base/base.jinja2" %}
{% from "base/macros.jinja2" import badge %}
{% macro body(element, trail) %}
<div class="breadcrumbs">
{% for node in trail|split("-") %}
{% if loop.first %}
Root
{% else %}
<a href="#{{ node }}"
onclick="anchorLink('{{ node }}')">{{ node }}</a>
{% endif %}
{% if not loop.last %}
<i class="bi-arrow-right-short"></i>
{% endif %}
{% endfor %}
</div>
{% if element.occurs[0] != 1 or element.occurs[1] != 1 %}
<div class="row">
<div class="col">
{{ badge("secondary", element.occurs|occurs_text) }}
</div>
</div>
{% endif %}
<div class="row">
<div class="col">
{{ badge("secondary", "Type: " + element.type|name) }}
</div>
</div>
<br/>
<div class="row">
<div class="col">
<span>{{ element|get_desc }}</span>
</div>
</div>
{% if element.type.has_complex_content() %}
{% for child in element.type.content|children %}
{{ render(child, trail) }}
{% endfor %}
{% endif %}
{% endmacro %}
{% macro render(element, trail) %}
<div class="row my-2">
<div class="col">
{% set trail=trail+"-"+element.name %}
{% set html_id=trail %}
<div class="accordion" id="accordion_{{ html_id }}">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_{{ html_id }}">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
data-bs-target="#{{ html_id }}" aria-expanded="false"
aria-controls="{{ html_id }}" onclick="setAnchor('#{{ html_id }}')">
<span class="property-name align-middle pb-1">{{ element.name | escape }}</span>
{% if element.occurs[0] == 1 and element.occurs[1] == 1 %}
{{ " " }}{{ badge("warning", "Required", "ms-2") }}
{% endif %}
</button>
</h2>
<div id="{{ trail }}" class="accordion-collapse collapse"
aria-labelledby="heading_{{ html_id }}"
data-parent="#accordion_{{ html_id }}">
<div class="accordion-body">
{% if element.parent != None and element.type.name == element.parent.parent.name %}
{{ badge("info", "<em>Recursive Reference</em>") }}
{% else %}
{{ body(element, trail) }}
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endmacro %}
{% block resources %}
{% include "base/schema/schema_includes.jinja2" %}
{% endblock %}
{% block onLoad %}anchorOnLoad();{% endblock %}
{% block content %}
<div class="row">
<div class="col text-center">
<h1>{{ page.title|title }}</h1>
</div>
</div>
<div class="row">
<div class="col">
{% for element in schema.elements.values() %}
{% for child in element.type.content %}
{{ render(child, element.name) }}
{% endfor %}
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="{{ "fav/ms-icon-70x70.png"|static }}"/>
<square150x150logo src="{{ "fav/ms-icon-150x150.png"|static }}"/>
<square310x310logo src="{{ "fav/ms-icon-70x70.png"|static }}"/>
<TileColor>#222222</TileColor>
</tile>
</msapplication>
</browserconfig>

View File

@ -1,5 +1,5 @@
Title: API
Sort-Priority: 40
Sort_Priority: 40
## How to use the API

View File

@ -1,5 +1,5 @@
Title: Detailing
Sort-Priority: 90
Sort_Priority: 90
## Details/Scatterer

View File

@ -1,5 +1,5 @@
Title: Dialogue
Sort-Priority: 50
Sort_Priority: 50
## Dialogue

View File

@ -1,5 +1,6 @@
{#~ Title:FAQ ~#}
{#~ Sort-Priority:95 ~#}
{#~ Sort_Priority:95 ~#}
{#~ Render_TOC:False ~#}
{% macro faq(id, q, a) %}
@ -38,7 +39,7 @@
faq(
"why-no-planet",
"Why doesn't my planet show up in game?",
"Have you checked the logs for errors? Are you using a program like [VSCode](https://code.visualstudio.com/){ target='_blank' } to write your configs that validates them against our schema to catch your errors? Do you incrementally test each new planet that you add, or did you write 10 json files and then try them all at once? If you're still not sure, come by our [Discord channel](https://discord.gg/9vE5aHxcF9){ target='_blank' } (`#nh-addon-discussion`) and we'll try to help out!"
"Have you checked the logs for errors? Are you using a program like [VSCode](https://code.visualstudio.com/){ target='_blank' } to write your configs that validates them against our schema to catch your errors? Do you incrementally test each new planet that you add, or did you write 10 json files and then try them all at once? If you're still not sure, come by our [Discord channel](https://discord.gg/wusTQYbYTc){ target='_blank' } (`#nh-addon-discussion`) and we'll try to help out!"
)
}}
{{

View File

@ -1,6 +1,6 @@
Title: Home
Out-File: index
Sort-Priority: 100
Out_File: index
Sort_Priority: 100
![New Horizons Logo]({{ 'images/home/home_logo.webp'|static }})
@ -19,12 +19,14 @@ Planets are created using a JSON file format structure, and placed in a folder c
it) in the location where New Horizons is installed (by default this folder doesn't exist, you have to create it within
the xen.NewHorizons directory).
You may want to get [VSCode](https://code.visualstudio.com/){ target="_blank" } if you are unfamiliar with the JSON language, as it will help highlight common errors.
To locate this directory, click the "⋮" symbol next to "New Horizons" in the Outer Wilds Mod Manager and then click "
show in explorer" in the pop-up.
![Click the three dots in the mod manager]({{ 'images/home/mod_manager_dots.webp'|static }})
![Click the three dots in the mod manager]({{ "images/home/mod_manager_dots.webp"|static }})
![Create a new folder named "planets"]({{ 'images/home/create_planets.webp'|static }})
![Create a new folder named "planets"]({{ "images/home/create_planets.webp"|static }})
Now that you have created your planets folder, this is where you will put your planet config files. A config file will
look something like this:
@ -116,6 +118,11 @@ it).
Check out the rest of the site for how to format planet, star system, dialogue, ship log, and translation files!
## Publishing Your Mod
Once your mod is complete, you can use the [addon creation tool](https://outerwildsmods.com/custom-worlds/create/){ target="_blank" } to upload your mod to the database.
Alternatively, you can use the [planet creation template](https://github.com/xen-42/ow-new-horizons-config-template#readme){ target="_blank" } GitHub template if you're familiar with Git and GitHub
## Helpful Resources
The texturemap/heightmap feature was inspired by the KSP mod Kopernicus. A lot of the same techniques that apply to

View File

@ -1,8 +1,6 @@
Title: Ship Log
Description: A guide to editing the ship log in New Horizons
Sort-Priority: 70
{% macro image(name) %}{{ ("images/ship_log/" + name)|static }}{% endmacro %}
Sort_Priority: 70
# Intro
Welcome! this page outlines how to create a custom ship log.
@ -35,7 +33,7 @@ An entry is a card you see in rumor mode, it represents a specific area or conce
village or the southern observatory on Brittle Hollow.
An entry is split up into facts, a fact can either be a rumor fact or an explore fact.
![entryExample]({{ image("entry_example.webp") }})
![entryExample]({{ "images/ship_log/entry_example.webp"|static }})
*In red you can see an entry, in green you can see the entry's facts*
### Curiosities
@ -44,14 +42,14 @@ Curiosities are entries that represent big ideas in the story, such as the ATP o
Non-curiosity entries have a Curiosity attribute that can be set to make the color of that entry match the color of the
curiosity (Like how everything regarding the Vessel is red)
![curiosityExample]({{ image("curiosity_example.webp") }})
![curiosityExample]({{ "images/ship_log/curiosity_example.webp"|static }})
*The Ash Twin Project is an example of a curiosity (internally it's called TIME_LOOP)*
### Child Entries
Entries can be children of other entries, meaning they'll be smaller.
![childEntryExample]({{ image("child_entry_example.webp") }})
![childEntryExample]({{ "images/ship_log/child_entry_example.webp"|static }})
*The murals at the old settlement on Brittle Hollow are examples of child entries*
## Rumor Facts
@ -59,13 +57,13 @@ Entries can be children of other entries, meaning they'll be smaller.
A rumor fact represents the information you might hear about a specific area or concept, usually, you get these through
dialogue or maybe by observing a faraway planet.
![rumorFactExample]({{ image("rumor_example.webp") }})
![rumorFactExample]({{ "images/ship_log/rumor_example.webp"|static }})
## Explore Facts
Explore facts represent the information you learn about a specific area or concept.
![exploreFactExample]({{ image("explore_example.webp") }})
![exploreFactExample]({{ "images/ship_log/explore_example.webp"|static }})
# The XML
@ -203,7 +201,7 @@ For example, if I want to change an entry with the ID of `EXAMPLE_ENTRY` and ano
}
```
![autoDetectiveMode]({{ image("auto_rumor_mode.webp") }})
![autoDetectiveMode]({{ "images/ship_log/auto_rumor_mode.webp"|static }})
*A set of entries laid out with auto mode*
## Images
@ -254,7 +252,7 @@ Colors for each curiosity is given in a list, so if I wanted the curiosity `EXAM
}
```
![curiosityColorChange]({{ image("change_color.webp") }})
![curiosityColorChange]({{ "images/ship_log/change_color.webp"|static }})
*The curiosity's color is changed to blue*
# Map Mode Options
@ -272,7 +270,7 @@ those planets are put in a column, then, each planet orbiting *those* planets ar
are. The order of each planet is determined by their semi-major axis, if two planets have the same semi-major axis then
they're sorted by order loaded in.
![autoMapMode]({{ image("auto_map_mode.webp") }})
![autoMapMode]({{ "images/ship_log/auto_map_mode.webp"|static }})
*An example system laid out with auto mode*
#### Offset
@ -345,7 +343,7 @@ second row (you can't select the sun, so it doesn't have a row or column). So, b
We say this planet is to the right of the sun station (putting in a position that is already occupied will override what
is in that position).
![navigationIndices]({{ image("map_indices.webp") }})
![navigationIndices]({{ "images/ship_log/map_indices.webp"|static }})
#### Overriding Vanilla Planets
@ -576,4 +574,4 @@ Adding an entry location is similar to adding a Reveal Volume:
}
```
![entryLocationExample]({{ image("entry_position.webp") }})
![entryLocationExample]({{ "images/ship_log/entry_position.webp"|static }})

View File

@ -1,5 +1,5 @@
Title: Translations
Sort-Priority: 60
Sort_Priority: 60
## Translations

View File

@ -1,5 +1,5 @@
Title: Update Planets
Sort-Priority: 80
Sort_Priority: 80
## Update Existing Planets

View File

@ -1,4 +0,0 @@
User-Agent: *
Allow: /
Sitemap: {{ "/sitemap.xml"|full_url }}

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 https://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
{% for item in content %}
<url>
<loc>{{ item.out_path|string|replace('\\', '/')|full_url }}</loc>
<priority>{{ item.sort_priority / 100 }}</priority>
</url>
{% endfor %}
</urlset>

View File

@ -1,49 +0,0 @@
{
"$schema": "https://json.schemastore.org/web-manifest-combined.json",
"name": "New Horizons Docs",
"short_name": "NH Docs",
"categories": ["games", "utilities"],
"start_url": ".",
"theme_color": "#333333",
"background_color": "#222222",
"lang": "en-US",
"description": "Documentation for creating planets with the New Horizons mod for Outer Wilds",
"icons": [
{
"src": "/fav/android-icon-36x36.png",
"sizes": "36x36",
"type": "image/png",
"density": "0.75"
},
{
"src": "/fav/android-icon-48x58.png",
"sizes": "48x48",
"type": "image/png",
"density": "1.0"
},
{
"src": "/fav/android-icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"density": "1.5"
},
{
"src": "/fav/android-icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"density": "2.0"
},
{
"src": "/fav/android-icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"density": "3.0"
},
{
"src": "/fav/android-icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"density": "4.0"
}
]
}

View File

@ -21,8 +21,7 @@ pre > code {
background: #555;
}
.accordion-button:not(.collapsed) {
color: #effff7 !important;
.accordion-button {
background-color: #2b2b2b !important;
}
@ -48,3 +47,7 @@ pre > code {
.accordion-item {
border: 1px solid rgba(0, 0, 0, 0.4);
}
.accordion-body {
background-color: #353535 !important;
}

View File

@ -1,101 +0,0 @@
import os
from datetime import datetime
from pathlib import Path
from shutil import rmtree
from jinja2 import Environment, select_autoescape, FileSystemLoader
from markdown import Markdown
from lib.Content.CSSStaticItem import CSSStaticItem
from lib.Content.HTMLPage import HTMLPage
from lib.Content.ImageStaticItem import ImageStaticItem
from lib.Content.JSONSchema import JSONSchema
from lib.Content.JSStaticItem import JSStaticItem
from lib.Content.MDPage import MDPage
from lib.Content.MetaItem import MetaItem, MinifiedMetaItem
from lib.Content.StaticItem import StaticItem
from lib.Content.XMLSchema import XMLSchema
print("Setup")
OUT_DIR = os.getenv("OUT_DIR", "/")
BASE_URL = os.getenv("BASE_URL", "")
GEN_TIME = datetime.now().strftime("%d/%m/%Y")
env = Environment(
loader=FileSystemLoader("content/"),
autoescape=select_autoescape(['jinja2'])
)
env.globals['OUT_DIR'] = OUT_DIR
static_scanners = (JSStaticItem, CSSStaticItem, ImageStaticItem)
static_extensions = {}
for scanner in static_scanners:
for ext in scanner.extensions:
static_extensions['.' + ext] = scanner
page_scanners = (MDPage, HTMLPage)
schema_scanners = (JSONSchema, XMLSchema)
meta_files = [MinifiedMetaItem(Path('browserconfig.jinja2'), '.xml'),
MinifiedMetaItem(Path('sitemap.jinja2'), '.xml'),
MetaItem(Path('robots.jinja2'), '.txt')]
router = {}
filter_md = Markdown(extensions=['extra'], output_format='html5')
env.filters.update({
'upper_first': lambda x: x[0].upper() + x[1:],
'static': lambda path: str(Path(OUT_DIR, path).as_posix()),
'route': lambda title: router.get(title.lower(), "#"),
'full_url': lambda relative: BASE_URL + (relative[1:] if relative[0] == "/" else relative),
'gen_time': lambda x: GEN_TIME,
'simple_md': lambda s: filter_md.convert(s),
'inline_md': lambda s: filter_md.convert(s)[3:-4].replace("<em>", "<span style=\"font-style: italic;\">").replace("</em>", "</span>")
})
MetaItem.initialize(env)
MinifiedMetaItem.initialize(env)
pages = []
schemas = []
static_files = []
print("Clearing Old Output")
if Path("out/").exists():
rmtree("out/", ignore_errors=True)
static_files = [static_extensions.get(f.suffix, StaticItem)(f) for f in Path('content/static/').glob("**/*.*")]
print("Scanning For Files")
for scanner in page_scanners:
new_pages = scanner.initialize(env)
for page in new_pages:
page.add_route(router, OUT_DIR)
pages += new_pages
for scanner in schema_scanners:
new_schemas = scanner.initialize(env)
for schema in new_schemas:
schema.add_route(router, OUT_DIR)
schemas += new_schemas
content = pages + schemas
hide_content = meta_files + static_files
print("Generating Pages")
pages.sort(key=lambda p: p.sort_priority, reverse=True)
schemas.sort(key=lambda s: s.title)
for item in content:
item.generate(pages=pages, schemas=schemas)
for meta_file in hide_content:
meta_file.env = env
meta_file.generate(content=content)
print("Done")

View File

@ -1,42 +0,0 @@
from os import getenv
from pathlib import Path
from markdown import Extension
from markdown.treeprocessors import Treeprocessor
from lib.Content.ImageStaticItem import ImageStaticItem
class BootstrapExtension(Extension):
def extendMarkdown(self, md, md_globals):
md.registerExtension(self)
self.processor = BootstrapTreeProcessor()
self.processor.md = md
self.processor.config = self.getConfigs()
md.treeprocessors.add('bootstrap', self.processor, '_end')
classes = {
'img': "img-fluid rounded mx-auto d-flex",
'table': "table-striped"
}
def process(node):
if node.tag in classes.keys():
node.set("class", classes[node.tag])
if node.tag == 'img' and "{{" not in node.get('src'):
size = ImageStaticItem.get_size(str(Path(node.get('src')).relative_to(getenv('OUT_DIR')).as_posix()))
node.set('width', str(size[0]))
node.set('height', str(size[1]))
for child in node:
process(child)
class BootstrapTreeProcessor(Treeprocessor):
def run(self, node):
for child in node:
process(child)
return node

View File

@ -1,58 +0,0 @@
from abc import ABC
from pathlib import Path
from htmlmin import minify
from jinja2 import Environment
class AbstractItem(ABC):
output_ext: str = '.html'
env: Environment
in_path: Path
out_path: Path
root_dir: Path
def __init__(self, in_path: Path, ext: str = None):
self.env = None
if ext is not None:
self.output_ext = ext
self.in_path = in_path
self.out_path = Path('out/', in_path.name).with_suffix(self.output_ext)
@classmethod
def initialize(cls, env: Environment) -> list:
raise NotImplementedError()
def render(self, **context) -> str:
raise NotImplementedError()
def _save(self, rendered: str):
self.out_path.parent.mkdir(mode=511, parents=True, exist_ok=True)
with self.out_path.open(mode='w+', encoding='utf-8') as file:
file.write(rendered)
def generate(self, **context) -> None:
print("Building:", self.in_path, "->", self.out_path)
self._save(self.render(**context))
def add_route(self, routes, out_dir):
pass
class MinifyMixin(AbstractItem, ABC):
MINIFY_SETTINGS = {
'remove_empty_space': True,
'keep_pre': True,
'remove_optional_attribute_quotes': False
}
def _save(self, rendered: str):
rendered = minify(rendered, **self.MINIFY_SETTINGS)
super(MinifyMixin, self)._save(rendered)

View File

@ -1,24 +0,0 @@
from abc import ABC
from pathlib import Path
from jinja2 import Template, Environment
from lib.Content.AbstractTemplatedItem import AbstractTemplatedItem
class AbstractSchemaItem(AbstractTemplatedItem, ABC):
root_dir = Path('schemas/')
def __init__(self, in_path: Path):
super().__init__(in_path)
self.out_path = Path('out/schemas/', self.out_path.relative_to('out'))
@classmethod
def initialize(cls, env: Environment):
new_pages = super(AbstractSchemaItem, cls).initialize(env)
for page in new_pages:
page.out_path = page.out_path.with_stem(page.title.replace(" ", "_").lower())
return new_pages
def render(self, template: Template, **context):
raise NotImplementedError()

View File

@ -1,53 +0,0 @@
from abc import ABC
from itertools import chain
from pathlib import Path
from jinja2 import Template, Environment
from lib.Content.AbstractItem import AbstractItem, MinifyMixin
class AbstractTemplatedItem(MinifyMixin, AbstractItem, ABC):
extensions: tuple[str]
title: str = None
description: str | None = None
sort_priority: int = None
render_toc: bool = False
table_of_contents: dict = {}
meta: dict = {
'title': None,
'description': None,
'sort_priority': 10
}
def load_metadata(self):
self.title = self.meta['title'] if self.meta['title'] is not None else self.in_path.stem
self.description = self.meta['description']
self.sort_priority = int(self.meta['sort_priority'])
@classmethod
def initialize(cls, env: Environment):
pages = []
file_paths = list(chain(*[Path('content/', cls.root_dir).glob(f'**/*.{ext}') for ext in cls.extensions]))
for path in file_paths:
new_page = cls(path)
new_page.env = env
new_page.load_metadata()
pages.append(new_page)
return pages
def inner_render(self, template: Template, **context):
return template.render(**context)
def render(self, **context):
container = self.env.get_template('base/page_template.jinja2')
template = self.env.get_template(str(self.in_path.relative_to(Path('content/')).as_posix()))
context.update({
'page': self,
'rendered': self.inner_render(template, **context),
'render_toc': self.render_toc
})
return container.render(**context)
def add_route(self, router, out_dir):
router[self.title.lower()] = out_dir + str(self.out_path.relative_to('out/'))

View File

@ -1,11 +0,0 @@
from rcssmin import cssmin
from lib.Content.StaticItem import MinifiedStaticItem
class CSSStaticItem(MinifiedStaticItem):
extensions = ('css',)
def minify(self, content):
return cssmin(content)

View File

@ -1,18 +0,0 @@
import re
from pathlib import Path
from lib.Content.AbstractTemplatedItem import AbstractTemplatedItem
class HTMLPage(AbstractTemplatedItem):
def load_metadata(self):
with self.in_path.open(mode='r', encoding='utf-8') as file:
content = file.read()
for match in re.findall(r"{#~(.*?)~#}", content, re.MULTILINE):
seperated = match.strip().split(':')
self.meta[seperated[0].lower().replace('-', '_')] = seperated[1]
super(HTMLPage, self).load_metadata()
root_dir = Path("pages/")
extensions = ('html', 'jinja2', 'jinja')

View File

@ -1,21 +0,0 @@
from pathlib import Path
from PIL import Image
from lib.Content.StaticItem import StaticItem
class ImageStaticItem(StaticItem):
extensions = ('png', 'jpg', 'jpeg', 'webp')
sizes = {}
@classmethod
def get_size(cls, stem):
return cls.sizes.get(stem, (0, 0))
def __init__(self, path: Path):
super().__init__(path)
with Image.open(self.in_path) as img:
self.sizes[str(self.out_path.relative_to('out/').as_posix())] = img.size

View File

@ -1,58 +0,0 @@
import json
import os
import sys
from pathlib import Path
from json_schema_for_humans.generate import generate_schemas_doc
from json_schema_for_humans.generation_configuration import GenerationConfiguration
from json_schema_for_humans.schema.schema_to_render import SchemaToRender
from json_schema_for_humans.template_renderer import TemplateRenderer
from lib.Content.AbstractSchemaItem import AbstractSchemaItem
SCHEMA_SETTINGS = GenerationConfiguration()
SCHEMA_SETTINGS.link_to_reused_ref = False
SCHEMA_SETTINGS.minify = False
class NoPrint:
def __enter__(self):
self._original_stdout = sys.stdout
sys.stdout = open(os.devnull, 'w')
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout.close()
sys.stdout = self._original_stdout
class JSONSchema(AbstractSchemaItem):
extensions = ('json',)
def load_metadata(self):
self.meta['sort_priority'] = 10
with self.in_path.open(mode='r', encoding='utf-8') as file:
self.meta['title'] = json.load(file).get('title', self.in_path.stem)
self.meta['description'] = "Schema for a " + self.meta['title'] + " in New Horizons"
super(JSONSchema, self).load_metadata()
def render(self, **context):
context.update({
'page': self
})
dumb_renderer = TemplateRenderer(SCHEMA_SETTINGS)
self.env.filters.update(dumb_renderer.template.environment.filters)
self.env.tests.update(dumb_renderer.template.environment.tests)
self.env.globals.update(dumb_renderer.template.environment.globals)
schemas = [SchemaToRender(self.in_path, None, None)]
schema_template = self.env.get_template(str(Path('base/schema/json/schema_base.jinja2').as_posix()))
template_renderer = TemplateRenderer(SCHEMA_SETTINGS, schema_template)
template_renderer.render = lambda inter: self.template_override(template_renderer, inter, **context)
with NoPrint():
rendered = generate_schemas_doc(schemas, template_renderer)
return rendered[str(self.in_path.name)]
def template_override(self, template: TemplateRenderer, intermediate_schema, **context):
template.template.environment.loader = self.env.loader
rendered = template.template.render(schema=intermediate_schema, config=SCHEMA_SETTINGS,
title=self.title + " Schema", **context)
return rendered

View File

@ -1,13 +0,0 @@
from rjsmin import jsmin
from lib.Content.StaticItem import MinifiedStaticItem
class JSStaticItem(MinifiedStaticItem):
extensions = ('js',)
def minify(self, content):
return jsmin(content)

View File

@ -1,43 +0,0 @@
from pathlib import Path
from markdown import Markdown
from lib.Content.AbstractTemplatedItem import AbstractTemplatedItem
from lib.BootstrapExtension import BootstrapExtension
class MDPage(AbstractTemplatedItem):
root_dir = Path("pages/")
extensions = ('md', 'markdown')
MARKDOWN_SETTINGS = {
'extensions': ['extra', 'toc', 'meta', BootstrapExtension()],
'output-format': 'html5'
}
def load_metadata(self):
md = self.__get_md()
with self.in_path.open(mode='r', encoding='utf-8') as file:
md.convert(file.read())
self.meta['title'] = md.Meta.get('title')[0]
self.meta['description'] = md.Meta.get('description', [None])[0]
self.render_toc = md.Meta.get('toc', ['True'])[0].strip().lower() == "true"
if self.render_toc:
self.table_of_contents = md.toc_tokens
raw_priority = md.Meta.get('sort-priority')
if raw_priority is not None:
self.meta['sort_priority'] = int(raw_priority[0])
out_name = md.Meta.get('out-file', None)
if out_name is not None:
self.out_path = self.out_path.with_stem(out_name[0])
super(MDPage, self).load_metadata()
def __get_md(self):
return Markdown(**self.MARKDOWN_SETTINGS)
def inner_render(self, template, **context):
rendered_markdown = super(MDPage, self).inner_render(template, **context)
md = self.__get_md()
return md.convert(rendered_markdown)

View File

@ -1,18 +0,0 @@
from jinja2 import Environment
from lib.Content.AbstractItem import AbstractItem, MinifyMixin
class MetaItem(AbstractItem):
@classmethod
def initialize(cls, env: Environment) -> list:
cls.env = env
def render(self, **context) -> str:
template = self.env.get_template(str(self.in_path.as_posix()))
return template.render(**context)
class MinifiedMetaItem(MinifyMixin, MetaItem):
pass

View File

@ -1,36 +0,0 @@
from abc import ABC
from pathlib import Path
class StaticItem:
extensions = ('',)
def __init__(self, path: Path):
self.in_path = path
self.out_path = Path('out/', path.relative_to('content/static/'))
self.out_path.parent.mkdir(parents=True, exist_ok=True)
def generate(self, **kwargs):
print("Building:", str(self.in_path), "->", str(self.out_path))
with self.in_path.open(mode='rb') as file:
content = file.read()
with self.out_path.open(mode='wb+') as file:
file.write(content)
class MinifiedStaticItem(StaticItem, ABC):
def __init__(self, path: Path):
super().__init__(path)
self.out_path = self.out_path.with_stem(self.out_path.stem + '.min')
def minify(self, content):
raise NotImplementedError()
def generate(self, **kwargs):
print("Building:", str(self.in_path), "->", str(self.out_path))
with self.in_path.open(mode='r') as file:
content = file.read()
with self.out_path.open(mode='w+') as file:
file.write(self.minify(content))

View File

@ -1,93 +0,0 @@
import os
import xmlschema
from jinja2 import Environment, UndefinedError
from xmlschema import XsdElement
from xmlschema.extras.codegen import AbstractGenerator, filter_method
__all__ = ('XMLSchema',)
from lib.Content.AbstractSchemaItem import AbstractSchemaItem
def children(group):
child = [child for child in group if child.__class__.__name__ == "XsdElement"]
for child_list in [children(inner_group) for inner_group in group if inner_group.__class__.__name__ == "XsdGroup"]:
child += child_list
return child
def ancestry(element):
if element.parent is None:
print(element.name)
return [element.name]
else:
if element.name is None:
return ancestry(element.parent)
else:
return [element.name] + ancestry(element.parent)
class HTMLConverter(AbstractGenerator):
formal_language = "html"
searchpaths = [os.getcwd() + "/content/"]
@staticmethod
@filter_method
def children(group):
return children(group)
@staticmethod
@filter_method
def id_path(element):
return '-'.join(reversed(ancestry(element)))
@staticmethod
@filter_method
def split(string, delim):
return string.split(delim)
@staticmethod
@filter_method
def get_desc(element: XsdElement):
try:
return str(element.annotation.documentation[0].text.strip())
except (UndefinedError, AttributeError):
return ""
@staticmethod
@filter_method
def occurs_text(occurs):
words = {
0: "Zero",
1: "One",
None: "Many"
}
return "Appears " + words[occurs[0]] + " To " + words[occurs[1]] + " " + ("Time" if occurs[1] == 1 else "Times")
def setup(self, other: Environment):
other.filters.update(self._env.filters)
other.globals.update(self._env.filters)
self._env = other
class XMLSchema(AbstractSchemaItem):
extensions = ('xsd', 'xml')
def load_metadata(self):
with self.in_path.open(mode='r', encoding='utf-8') as file:
file.readline()
line = file.readline()
if len(line.strip()) != 0 and '<!--' in line and '-->' in line:
self.meta['title'] = line.replace('<!--', '').replace('-->', '').strip()
super(XMLSchema, self).load_metadata()
def render(self, **context):
context.update({
'page': self
})
with self.in_path.open(mode='r', encoding='utf-8') as file:
schema = xmlschema.XMLSchema(file)
converter = HTMLConverter(schema)
converter.setup(self.env)
return converter.render('base/schema/xml/schema_base.jinja2', global_vars=context)[0]

View File

View File

@ -1,19 +0,0 @@
import re
def camel_to_pretty(raw):
return ' '.join(re.findall(r'[A-Z](?:[a-z]+|[A-Z]*(?=[A-Z]|$))', raw))
def pretty_title(raw: str) -> str:
if '_' in raw:
return ' '.join(x[0].upper() + x[1:] for x in raw.split('_'))
elif any(x.isupper() for x in raw):
if raw[0].islower():
new_raw = raw[0].upper() + raw[1:]
else:
new_raw = raw
return camel_to_pretty(new_raw)