Merge branch 'dev'

This commit is contained in:
JohnCorby 2023-07-27 17:03:57 -07:00
commit 10c912139a
23 changed files with 255 additions and 164 deletions

91
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,91 @@
name: Create Release
on:
workflow_dispatch:
inputs:
prerelease:
description: Prerelease
type: boolean
bypassCheck:
description: Bypass Version Check
type: boolean
permissions:
contents: write
env:
PROJ_USERNAME: Raicuparta
PROJ_NAME: QuantumSpaceBuddies
REAL_PROJ_NAME: QSB
jobs:
pre_job:
name: Check For Other Releases
outputs:
version: ${{ steps.out.outputs.version }}
exists: ${{ steps.out.outputs.exists }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: "actions/checkout@v3"
- name: Fetch
run: git fetch
- name: Read Manifest
id: read-manifest
run: echo "manifest=$(< ./${{ env.REAL_PROJ_NAME }}/manifest.json sed ':a;N;$!ba;s/\n/ /g')" >> $GITHUB_OUTPUT
- name: Check For Release
id: check-tag
run: echo "exists=$(git ls-remote --exit-code --tags origin ${{ env.TAG }} >/dev/null 2>&1 && echo true || echo false)" >> $GITHUB_OUTPUT
env:
TAG: "v${{fromJson(steps.read-manifest.outputs.manifest).version}}"
- name: Output Version Info
id: out
run: |
echo "version=${{fromJson(steps.read-manifest.outputs.manifest).version}}" >> $GITHUB_OUTPUT
echo "exists=${{steps.check-tag.outputs.exists}}" >> $GITHUB_OUTPUT
- name: Error
if: ${{ steps.out.outputs.exists != 'false' && (!inputs.bypassCheck) }}
run: echo "::error file=manifest.json,title=Refusing to Release::Your mod was not released because there is already a release with the version in manifest.json"
release:
needs: pre_job
if: ${{ (needs.pre_job.outputs.version != '0.0.0') && (needs.pre_job.outputs.exists == 'false') || (inputs.bypassCheck) }}
name: Create Release
runs-on: windows-latest
steps:
- name: Checkout
uses: "actions/checkout@v3"
- name: Setup .NET
uses: "actions/setup-dotnet@v3"
- name: Remove .csproj.user
run: if (Test-Path ${{ env.REAL_PROJ_NAME }}/${{ env.REAL_PROJ_NAME }}.csproj.user) { rm ${{ env.REAL_PROJ_NAME }}/${{ env.REAL_PROJ_NAME }}.csproj.user }
- name: Build Mod
run: dotnet build -c Release
- name: Upload Artifact
uses: "actions/upload-artifact@v3"
with:
name: "${{ env.PROJ_USERNAME }}.${{ env.PROJ_NAME }}"
path: "${{ env.REAL_PROJ_NAME }}/bin/Release"
- name: Zip For Release
run: 7z a ${{ env.PROJ_USERNAME }}.${{ env.PROJ_NAME }}.zip ./${{ env.REAL_PROJ_NAME }}/bin/Release/**
- name: Create Release
uses: "ncipollo/release-action@v1"
with:
allowUpdates: true
commit: ${{ github.ref_name }}
tag: v${{ needs.pre_job.outputs.version }}
name: Version ${{ needs.pre_job.outputs.version }}
omitBodyDuringUpdate: true
artifacts: "${{ env.PROJ_USERNAME}}.${{ env.PROJ_NAME }}.zip"
draft: true
prerelease: ${{ inputs.prerelease }}

98
DEVELOPMENT.md Normal file
View File

@ -0,0 +1,98 @@
> :warning: Warning! :warning:
Mod development needs a powerful PC!
Unexpected errors and issues may occur when editing networking code.
Running multiple instances of the game can be very taxing on your computer.
We're not responsible if you push your PC too hard.
## Prerequisites
- Visual Studio 2022.
- Epic or Steam version of Outer Wilds.
- Keyboard with numpad for in-game debug actions.
We recommend using the Outer Wilds Mod Manager, but you can use OWML on its own if you want.
## Cloning and configuration
- Clone QSB's source code.
- Copy the file `DevEnv.template.targets` and rename it to `DevEnv.targets`.
- In `DevEnv.targets`, edit the entry for `<OwmlDir>` to point to your installation of OWML. This should be the folder named `OWML`. If using the manager, you can find this directory by :
- Legacy Manager : Press the "Mods Directory" button and go up a folder.
- New Manager : Press the "..." button at the top, and select "Show OWML Folder".
- `QSB.sln` should now be ready to open. ***This solution needs to be opened with Visual Studio 2022 or higher!***
## Steam
If using the Steam version of Outer Wilds, you will need to create a file to allow you to run multiple instances of the game.
- Navigate to your game install folder. You can find this by right-clicking on the game in Steam, and going `Manage > Browse local files`.
- Create a file named `steam_appid.txt`.
- In this file, write `753640` and save.
This file will override some Steam DRM features and allow the game to be ran multiple times at once.
## Building
Simply build the solution normally. (`Build > Build Solution` or CTRL-SHIFT-B)
The files will automatically be copied over to your OWML installation and be ready to play - no DLL copying needed.
For documentation reasons, here is the build flow :
- MirrorWeaver is built.
- EpicOnlineTransport is built.
- EpicRerouter is built.
- QSB is built.
- Any `.exe.config` files are removed from the build.
- QSB.dll is processed ("weaved") by MirrorWeaver. This injects all the boilerplate code that Mirror needs to function.
- If needed/possible, any `.dll` or `.exe` files are copied to the Unity project.
## Debugging
### Debug Actions :
Hold Q and press :
- Numpad 1 - Teleport to nearest player.
- Numpad 2 - If holding LeftShift, warp to the dreamworld Vault fire. If not, warp to the Endless Canyon.
- Numpad 3 - Unlock the Sealed Vault.
- Numpad 4 - Damage the ship's electrical system.
- Numpad 5 - Trigger the supernova.
- Numpad 6 - Set the flags for having met Solanum and the Prisoner.
- Numpad 7 - Warp to the Vessel.
- Numpad 8 - Insert the Advanced Warp Core into the Vessel.
- Numpad 9 - If holding LeftShift, load the SolarSystem scene. If not, load the EyeOfTheUniverse scene.
- Numpad 0 - Revive a random dead player.
### Debug Settings :
Create a file called `debugsettings.json` in the mod folder.
The template for this file is this :
```json
{
"dumpWorldObjects": false,
"instanceIdInLogs": false,
"hookDebugLogs": false,
"avoidTimeSync": false,
"autoStart": false,
"kickEveryone": false,
"disableLoopDeath": false,
"debugMode": false,
"drawGui": false,
"drawLines": false,
"drawLabels": false,
"drawQuantumVisibilityObjects": false,
"drawGhostAI": false,
"greySkybox": false
}
```
- dumpWorldObjects - Creates a file with information about the WorldObjects that were created.
- instanceIdInLogs - Appends the game instance id to every log message sent.
- hookDebugLogs - Print Unity logs and warnings.
- avoidTimeSync - Disables the syncing of time.
- autoStart - Host/connect automatically for faster testing.
- kickEveryone - Kick anyone who joins a game.
- disableLoopDeath - Make it so the loop doesn't end when everyone is dead.
- debugMode - Enables debug mode. If this is set to `false`, none of the following settings do anything.
- drawGui - Draws a GUI at the top of the screen that gives information on many things.
- drawLines - Draws gizmo-esque lines around things. Indicates reference sectors/transforms, triggers, etc. LAGGY.
- drawLabels - Draws GUI labels attached to some objects. LAGGY.
- drawQuantumVisibilityObjects - Indicates visibility objects with an orange shape.
- drawGhostAI - Draws debug lines and labels just for the ghosts.
- greySkybox - Turns the skybox grey. Useful in the Eye, where it's pretty dark.

View File

@ -8,7 +8,7 @@
<PackageLicenseFile>License.md</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" IncludeAssets="compile" />
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.457" IncludeAssets="compile" />
<Reference Include="../Mirror/*.dll" />
</ItemGroup>
<ItemGroup>

View File

@ -14,7 +14,7 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" IncludeAssets="compile" />
<PackageReference Include="OWML" Version="2.9.0" IncludeAssets="compile" />
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.457" IncludeAssets="compile" />
<PackageReference Include="OWML" Version="2.9.3" IncludeAssets="compile" />
</ItemGroup>
</Project>

View File

@ -8,8 +8,8 @@
<Copyright></Copyright>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" />
<PackageReference Include="OWML" Version="2.9.0" />
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.457" />
<PackageReference Include="OWML" Version="2.9.3" />
<Reference Include="../Mirror/*.dll" />
</ItemGroup>
<ItemGroup>

View File

@ -8,6 +8,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2569F98D-F671-42AA-82DE-505B05CDCEF2}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
DEVELOPMENT.md = DEVELOPMENT.md
LICENSE = LICENSE
README.md = README.md
TRANSLATING.md = TRANSLATING.md
@ -15,9 +16,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MirrorWeaver", "MirrorWeaver\MirrorWeaver.csproj", "{DA8A467E-15BA-456C-9034-6EB80BAF1FF9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicOnlineTransport", "EpicOnlineTransport\EpicOnlineTransport.csproj", "{971AA4A1-6729-40DE-AADF-2754F1E8783A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EpicOnlineTransport", "EpicOnlineTransport\EpicOnlineTransport.csproj", "{971AA4A1-6729-40DE-AADF-2754F1E8783A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpicRerouter", "EpicRerouter\EpicRerouter.csproj", "{639EFAEE-C4A1-4DA2-8457-D0472A9F6343}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EpicRerouter", "EpicRerouter\EpicRerouter.csproj", "{639EFAEE-C4A1-4DA2-8457-D0472A9F6343}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -8,6 +8,8 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_USING/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/CASE_BLOCK_BRACES/@EntryValue">NEXT_LINE_SHIFTED_2</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QSB/@EntryIndexedValue">QSB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UWP/@EntryIndexedValue">UWP</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>

View File

@ -42,7 +42,7 @@ public class PlayerDeathMessage : QSBMessage<DeathType>
var deathMessage = Necronomicon.GetPhrase(Data, NecronomiconIndex);
if (deathMessage != null)
{
MultiplayerHUDManager.Instance.WriteMessage(string.Format(deathMessage, playerName), Color.grey);
MultiplayerHUDManager.Instance.WriteSystemMessage(string.Format(deathMessage, playerName), Color.grey);
}
RespawnManager.Instance.OnPlayerDeath(player);

View File

@ -239,7 +239,7 @@ public class RespawnOnDeath : MonoBehaviour
}
var cloak = Locator.GetCloakFieldController();
// visible stranger and maybe NH disables cloak
// visible stranger disables cloak
if (cloak)
{
cloak._playerInsideCloak = false;

View File

@ -8,7 +8,7 @@ using UnityEngine;
namespace QSB.HUD.Messages;
internal class ChatMessage : QSBMessage<(string message, Color color)>
public class ChatMessage : QSBMessage<(string message, Color color)>
{
public ChatMessage(string msg, Color color) : base((msg, color)) { }

View File

@ -23,6 +23,7 @@ internal class MultiplayerHUDManager : MonoBehaviour, IAddComponentOnStart
private Transform _textChat;
private InputField _inputField;
private Material _markerMaterial;
private bool _ready;
public static Sprite UnknownSprite;
public static Sprite DeadSprite;
@ -64,6 +65,11 @@ internal class MultiplayerHUDManager : MonoBehaviour, IAddComponentOnStart
Interloper = QSBCore.HUDAssetBundle.LoadAsset<Sprite>("Assets/MULTIPLAYER_UI/playerbox_interloper.png");
WhiteHole = QSBCore.HUDAssetBundle.LoadAsset<Sprite>("Assets/MULTIPLAYER_UI/playerbox_whitehole.png");
SpaceSprite = QSBCore.HUDAssetBundle.LoadAsset<Sprite>("Assets/MULTIPLAYER_UI/playerbox_space.png");
QSBSceneManager.OnPostSceneLoad += (OWScene old, OWScene newScene) =>
{
_ready = false;
};
}
private const int LINE_COUNT = 11;
@ -77,8 +83,21 @@ internal class MultiplayerHUDManager : MonoBehaviour, IAddComponentOnStart
private readonly ListStack<(string msg, Color color)> _messages = new(false);
private float _lastMessageTime;
// this just exists so i can patch this in my tts addon
// perks of being a qsb dev :-)
public void WriteSystemMessage(string message, Color color)
{
WriteMessage(message, color);
}
public void WriteMessage(string message, Color color)
{
// dont write messages when not ready
if (!_ready)
{
return;
}
/* Tricky problem to solve.
* - 11 available lines for text to fit onto
* - Each line can be max 41 characters
@ -307,6 +326,8 @@ internal class MultiplayerHUDManager : MonoBehaviour, IAddComponentOnStart
_lines.Clear();
_messages.Clear();
_textChat.GetComponent<CanvasGroup>().alpha = 0;
_ready = true;
}
public void UpdateMinimapMarkers(Minimap minimap)
@ -439,7 +460,7 @@ internal class MultiplayerHUDManager : MonoBehaviour, IAddComponentOnStart
Destroy(player.HUDBox?.gameObject);
Destroy(player.MinimapPlayerMarker);
WriteMessage(string.Format(QSBLocalization.Current.PlayerLeftTheGame, player.Name), Color.yellow);
WriteSystemMessage(string.Format(QSBLocalization.Current.PlayerLeftTheGame, player.Name), Color.yellow);
}
private PlanetTrigger CreateTrigger(string parentPath, HUDIcon icon)

View File

@ -7,7 +7,8 @@ public abstract class QSBMessage
/// <summary>
/// set automatically by Send
/// </summary>
protected internal uint From;
// public so it can be accessed by a patch
public uint From;
/// <summary>
/// (default) uint.MaxValue = send to everyone <br/>
/// 0 = send to host
@ -45,7 +46,8 @@ public abstract class QSBMessage
public abstract class QSBMessage<D> : QSBMessage
{
protected D Data { get; private set; }
// public so it can be accessed by a patch
public D Data { get; private set; }
protected QSBMessage(D data) => Data = data;
public override void Serialize(NetworkWriter writer)

View File

@ -1,7 +1,6 @@
using Cysharp.Threading.Tasks;
using QSB.MeteorSync.WorldObjects;
using QSB.WorldSync;
using System.Linq;
using System.Threading;
namespace QSB.MeteorSync;
@ -17,9 +16,7 @@ public class MeteorManager : WorldObjectManager
// wait for all late initializers (which includes meteor launchers) to finish
await UniTask.WaitUntil(() => LateInitializerManager.isDoneInitializing, cancellationToken: ct);
// NH can make multiple so ensure its the stock whitehole
var whiteHole = QSBWorldSync.GetUnityObjects<AstroObject>().First(x => x.GetAstroObjectName() == AstroObject.Name.WhiteHole);
WhiteHoleVolume = whiteHole?.GetComponentInChildren<WhiteHoleVolume>();
WhiteHoleVolume = QSBWorldSync.GetUnityObject<WhiteHoleVolume>();
QSBWorldSync.Init<QSBFragment, FragmentIntegrity>();
QSBWorldSync.Init<QSBMeteorLauncher, MeteorLauncher>();
QSBWorldSync.Init<QSBMeteor, MeteorController>();

View File

@ -37,13 +37,6 @@ internal class ModelShipManager : WorldObjectManager
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
{
// NH can remove this
var modelShip = QSBWorldSync.GetUnityObject<RemoteFlightConsole>()._modelShipBody;
if (!modelShip)
{
return;
}
if (QSBCore.IsHost)
{
Instantiate(QSBNetworkManager.singleton.ModelShipPrefab).SpawnWithServerOwnership();

View File

@ -127,7 +127,7 @@ public class PlayerJoinMessage : QSBMessage
var player = QSBPlayerManager.GetPlayer(From);
player.Name = PlayerName;
MultiplayerHUDManager.Instance.WriteMessage(string.Format(QSBLocalization.Current.PlayerJoinedTheGame, player.Name), Color.green);
MultiplayerHUDManager.Instance.WriteSystemMessage(string.Format(QSBLocalization.Current.PlayerJoinedTheGame, player.Name), Color.green);
DebugLog.DebugWrite($"{player} joined. qsbVersion:{QSBVersion}, gameVersion:{GameVersion}, dlcInstalled:{DlcInstalled}", MessageType.Info);
}

View File

@ -36,15 +36,15 @@ internal class PlayerKickMessage : QSBMessage<string>
{
if (QSBPlayerManager.PlayerExists(PlayerId))
{
MultiplayerHUDManager.Instance.WriteMessage(string.Format(QSBLocalization.Current.PlayerWasKicked, QSBPlayerManager.GetPlayer(PlayerId).Name), Color.red);
MultiplayerHUDManager.Instance.WriteSystemMessage(string.Format(QSBLocalization.Current.PlayerWasKicked, QSBPlayerManager.GetPlayer(PlayerId).Name), Color.red);
return;
}
MultiplayerHUDManager.Instance.WriteMessage(string.Format(QSBLocalization.Current.PlayerWasKicked, PlayerId), Color.red);
MultiplayerHUDManager.Instance.WriteSystemMessage(string.Format(QSBLocalization.Current.PlayerWasKicked, PlayerId), Color.red);
return;
}
MultiplayerHUDManager.Instance.WriteMessage(string.Format(QSBLocalization.Current.KickedFromServer, Data), Color.red);
MultiplayerHUDManager.Instance.WriteSystemMessage(string.Format(QSBLocalization.Current.KickedFromServer, Data), Color.red);
MenuManager.Instance.OnKicked(Data);
NetworkClient.Disconnect();

View File

@ -79,7 +79,7 @@ public class QSBCore : ModBehaviour
{
// incompatible mods
"Raicuparta.NomaiVR",
// "xen.NewHorizons",
"xen.NewHorizons",
"Vesper.AutoResume",
"Vesper.OuterWildsMMO",
"_nebula.StopTime",
@ -308,32 +308,3 @@ public class QSBCore : ModBehaviour
}
}
}
/*
* _nebula's music thanks
* I listen to music constantly while programming/working - here's my thanks to them for keeping me entertained :P
*
* Wintergatan
* HOME
* C418
* Lupus Nocte
* Max Cooper
* Darren Korb
* Harry Callaghan
* Toby Fox
* Andrew Prahlow
* Valve (Mike Morasky, Kelly Bailey)
* Joel Nielsen
* Vulfpeck
* Detektivbyrån
* Ben Prunty
* ConcernedApe
* Jake Chudnow
* Murray Gold
* Teleskärm
* Daft Punk
* Natalie Holt
* WMD
* Woody Jackson
* Brian David Gilbert
*/

View File

@ -91,15 +91,11 @@ public class QSBSectorManager : WorldObjectManager
// time loop spinning ring
{
// NH can remove this
var TimeLoopRing_Body = GameObject.Find("TimeLoopRing_Body");
if (TimeLoopRing_Body)
{
var Sector_TimeLoopInterior = GameObject.Find("Sector_TimeLoopInterior").GetComponent<Sector>();
// use the same trigger as the parent sector
FakeSector.Create(TimeLoopRing_Body, Sector_TimeLoopInterior,
x => x._triggerRoot = Sector_TimeLoopInterior._triggerRoot);
}
var Sector_TimeLoopInterior = GameObject.Find("Sector_TimeLoopInterior").GetComponent<Sector>();
// use the same trigger as the parent sector
FakeSector.Create(TimeLoopRing_Body, Sector_TimeLoopInterior,
x => x._triggerRoot = Sector_TimeLoopInterior._triggerRoot);
}
// TH elevators

View File

@ -184,6 +184,11 @@ public class ShipManager : WorldObjectManager
private void UpdateElectricalComponent()
{
if (ShipElectricalComponent == null)
{
return;
}
var electricalSystem = ShipElectricalComponent._electricalSystem;
var damaged = ShipElectricalComponent._damaged;

View File

@ -22,11 +22,6 @@ internal class OccasionalManager : WorldObjectManager
foreach (var proxy in cannon._realDebrisSectorProxies)
{
// NH can remove these
if (!proxy)
{
continue;
}
SpawnOccasional(proxy.transform.root.GetAttachedOWRigidbody(), gdBody);
}

View File

@ -208,8 +208,7 @@ public static class QSBWorldSync
{
// So objects have time to be deleted, made, whatever
// i.e. wait until Start has been called
// TODO: see if this number of frames actually works. TWEAK!
Delay.RunFramesLater(10, () => BuildWorldObjects(loadScene).Forget());
Delay.RunNextFrame(() => BuildWorldObjects(loadScene).Forget());
}
};

View File

@ -7,8 +7,8 @@
"body": "- Disable *all* other mods. (Can heavily affect performance)\n- Make sure you are not running any other network-intensive applications."
},
"uniqueName": "Raicuparta.QuantumSpaceBuddies",
"version": "0.29.0",
"owmlVersion": "2.9.0",
"version": "0.29.1",
"owmlVersion": "2.9.3",
"dependencies": [ "_nebula.MenuFramework", "JohnCorby.VanillaFix" ],
"pathsToPreserve": [ "debugsettings.json" ],
"requireLatestVersion": true

View File

@ -19,13 +19,13 @@ Spoilers within!
### Easy installation (recommended)
- [Install the Outer Wilds Mod Manager](https://github.com/Raicuparta/ow-mod-manager#how-do-i-use-this);
- [Install the Outer Wilds Mod Manager](https://outerwildsmods.com/mod-manager/);
- Install Quantum Space Buddies from the mod list displayed in the application;
- If you can't get the mod manager to work, follow the instructions for manual installation.
### Manual installation
- [Install OWML](https://github.com/amazingalek/owml#installation);
- [Install OWML](https://github.com/ow-mods/owml#installation);
- [Download the latest Quantum Space Buddies release](https://github.com/misternebula/quantum-space-buddies/releases/latest);
- Extract the `QSB` directory to the `OWML/Mods` directory;
- Run `OWML.Launcher.exe` to start the game.
@ -47,7 +47,7 @@ Spoilers within!
## Frequently Asked Questions
### I keep timing out when trying to connect!
Check the mod settings for "Use KCP Transport". You have to forward port 7777 as TCP/UDP, or use Hamachi. ALL PLAYERS MUST HAVE THIS AS THE SAME VALUE.
Check the mod settings for "Use KCP Transport". You have to forward port 7777 as TCP/UDP, or use Hamachi. ***All players must either be using KCP, or not using KCP.***
### Requirements
- Latest version of OWML.
@ -89,102 +89,22 @@ QSB is a fully synced game. The other players are actually there in the world, a
Outer Wilds Online is easier to set up, but much more basic in its features. The other players cannot affect your game, and do not contribute to anything in your save. The loop is entirely per-player.
### Why would someone make this mod? Seems like a lot of effort for no reward.
Good question.
Let me know if you find an answer.
**Update**: a plausible answer is the enjoyment you get seeing/hearing about others playing with their friends :)
## Translating
See [TRANSLATING.md](TRANSLATING.md)
## Development Setup
## Development Setup / Contributing
- [Download the Outer Wilds Mod Manager](https://github.com/raicuparta/ow-mod-manager) and install it anywhere you like;
- Install OWML using the Mod Manager
- Clone QSB's source
- Open the file `DevEnv.targets` in your favorite text editor
- (optional if copying built dlls manually) Edit the entry `<OwmlDir>` to point to your OWML directory (it is installed inside the Mod Manager directory)
- (optional if no unity project) Edit the entry `<UnityAssetsDir>` to point to the Assets folder of the QSB unity project
- Open the project solution file `QSB.sln` in Visual Studio 2022
If developing with the Steam version of Outer Wilds you can't run multiple instances of the game by default. To do so, create a file called `steam_appid.txt` in your Outer Wilds directory and write `753640` inside it, then run the exe directly.
A powerful PC is needed for development, due to the high amount of RAM and CPU needed to run 2 or 3 instances of modded Outer Wilds.
It is also recommended to lower all graphics settings to minimum, be in windowed mode, and lower resolution to roughly a quarter of your monitor space. This lets you run multiple instances of Outer Wilds to quickly test QSB.
Some debugging options exist to make things easier. These come in the form of actions and settings.
### Debug Actions :
Hold Q and press :
- Numpad 1 - Teleport to nearest player.
- Numpad 2 - If holding LeftShift, warp to the dreamworld Vault fire. If not, warp to the Endless Canyon.
- Numpad 3 - Unlock the Sealed Vault.
- Numpad 4 - Damage the ship's electrical system.
- Numpad 5 - Trigger the supernova.
- Numpad 6 - Set the flags for having met Solanum and the Prisoner.
- Numpad 7 - Warp to the Vessel.
- Numpad 8 - Insert the Advanced Warp Core into the Vessel.
- Numpad 9 - If holding LeftShift, load the SolarSystem scene. If not, load the EyeOfTheUniverse scene.
- Numpad 0 - Revive a random dead player.
### Debug Settings :
Create a file called `debugsettings.json` in the mod folder.
The template for this file is this :
```
{
"dumpWorldObjects": false,
"instanceIdInLogs": false,
"hookDebugLogs": false,
"avoidTimeSync": false,
"autoStart": false,
"kickEveryone": false,
"disableLoopDeath": false,
"debugMode": false,
"drawGui": false,
"drawLines": false,
"drawLabels": false,
"drawQuantumVisibilityObjects": false,
"drawGhostAI": false,
"greySkybox": false
}
```
- dumpWorldObjects - Creates a file with information about the WorldObjects that were created.
- instanceIdInLogs - Appends the game instance id to every log message sent.
- hookDebugLogs - Print Unity logs and warnings.
- avoidTimeSync - Disables the syncing of time.
- autoStart - Host/connect automatically for faster testing.
- kickEveryone - Kick anyone who joins a game.
- disableLoopDeath - Make it so the loop doesn't end when everyone is dead.
- debugMode - Enables debug mode. If this is set to `false`, none of the following settings do anything.
- drawGui - Draws a GUI at the top of the screen that gives information on many things.
- drawLines - Draws gizmo-esque lines around things. Indicates reference sectors/transforms, triggers, etc. LAGGY.
- drawLabels - Draws GUI labels attached to some objects. LAGGY.
- drawQuantumVisibilityObjects - Indicates visibility objects with an orange shape.
- drawGhostAI - Draws debug lines and labels just for the ghosts.
- greySkybox - Turns the skybox grey. Useful in the Eye, where it's pretty dark.
**Warning : Mod development can lead to unexpected errors in your computer system.**
- **When editing the networking code, mistakes can lead to QSB overwhelming your network connection with excess packets**.
- **Too high RAM usage will lead to Outer Wilds sticking at ~31% loading, then crashing**.
- **There have been instances of graphics cards crashing, and needing to be disabled/re-enabled from Device Manager.**
See [DEVELOPMENT.md](DEVELOPMENT.md)
## Authors and Special Thanks
### Authors
- [\_nebula](https://github.com/misternebula) - Developer of v0.3.0 onwards
- [JohnCorby](https://github.com/JohnCorby) - Co-developer of v0.13.0 onwards.
- [AmazingAlek](https://github.com/amazingalek) - Developer of v0.1.0 - v0.7.1.
- [Raicuparta](https://github.com/Raicuparta) - Developer of v0.1.0 - v0.2.0.
- [\_nebula](https://github.com/misternebula) - Lead Dev *(v0.3.0 onwards.)*
- [JohnCorby](https://github.com/JohnCorby) - Lead Dev *(v0.13.0 onwards)*
- [AmazingAlek](https://github.com/amazingalek) - Ex-Developer *(v0.1.0 - v0.7.1)*
- [Raicuparta](https://github.com/Raicuparta) - Ex-Developer *(v0.1.0 - v0.2.0)*
### Contributers