mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Merge branch 'dev' into coloured-splashes
This commit is contained in:
commit
7cb47ec1b1
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1,2 +1,2 @@
|
||||
patreon: ownh
|
||||
patreon: xen42
|
||||
custom: ["https://paypal.me/xen42"]
|
||||
|
||||
10
.github/workflows/build.yaml
vendored
10
.github/workflows/build.yaml
vendored
@ -29,10 +29,10 @@ jobs:
|
||||
schemas_changed: ${{ steps.changed_files.outputs.files_changed }}
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v4
|
||||
|
||||
# Disable Strong Name Verification to let us pull a switch-a-roo
|
||||
- name: Disable strong name validation
|
||||
@ -51,19 +51,19 @@ jobs:
|
||||
run: rm .\NewHorizons\bin\${{ inputs.build_type }}\NewHorizons.xml
|
||||
|
||||
- name: Upload Mod Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: xen.NewHorizons.${{ inputs.build_type }}
|
||||
path: .\NewHorizons\bin\${{ inputs.build_type }}
|
||||
|
||||
- name: Upload Schemas Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NewHorizons-Schemas-${{ inputs.build_type }}
|
||||
path: .\NewHorizons\Schemas
|
||||
|
||||
- name: Verify Changed Schemas
|
||||
uses: tj-actions/verify-changed-files@v17
|
||||
uses: tj-actions/verify-changed-files@v20
|
||||
id: changed_files
|
||||
with:
|
||||
files: NewHorizons/Schemas/**
|
||||
|
||||
8
.github/workflows/docs_build.yml
vendored
8
.github/workflows/docs_build.yml
vendored
@ -29,10 +29,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Download Schemas
|
||||
if: ${{ inputs.schemas_artifact != 'null' }}
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.schemas_artifact }}
|
||||
path: NewHorizons/Schemas
|
||||
@ -41,7 +41,7 @@ jobs:
|
||||
cp docs/package.json .
|
||||
cp docs/pnpm-lock.yaml .
|
||||
- name: Build Site
|
||||
uses: withastro/action@v1
|
||||
uses: withastro/action@v2
|
||||
with:
|
||||
path: ./docs
|
||||
package-manager: pnpm@latest
|
||||
@ -55,4 +55,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
4
.github/workflows/release_build.yml
vendored
4
.github/workflows/release_build.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
- name: Read Manifest
|
||||
id: read-manifest
|
||||
uses: notiz-dev/github-action-json-property@release
|
||||
@ -66,7 +66,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download Asset
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: xen.NewHorizons.Release
|
||||
path: xen.NewHorizons
|
||||
|
||||
4
.github/workflows/update_schemas.yml
vendored
4
.github/workflows/update_schemas.yml
vendored
@ -18,12 +18,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.SCHEMAS_TOKEN }}
|
||||
|
||||
- name: Download Artifact
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.artifact_name }}
|
||||
path: NewHorizons/Schemas/
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 128 KiB |
@ -1,17 +1,28 @@
|
||||
{
|
||||
"name" : "Ship",
|
||||
"$schema": "https://raw.githubusercontent.com/xen-42/outer-wilds-new-horizons/master/NewHorizons/body_schema.json",
|
||||
"Props" :
|
||||
{
|
||||
"dialogue": [
|
||||
{
|
||||
"position":{"x": -0.3071011, "y": 2.741472, "z": -4.005298},
|
||||
"radius": 0,
|
||||
"remoteTriggerRadius": 1,
|
||||
"xmlFile":"Assets/WarpDriveDialogue.xml",
|
||||
"remoteTriggerPosition": {"x": -0.05656214, "y": 0.5362684, "z": 0.5467669},
|
||||
"blockAfterPersistentCondition" : "KnowsAboutWarpDrive"
|
||||
}
|
||||
]
|
||||
}
|
||||
"name": "Ship",
|
||||
"$schema": "https://raw.githubusercontent.com/Outer-Wilds-New-Horizons/new-horizons/main/NewHorizons/Schemas/body_schema.json",
|
||||
"Props": {
|
||||
"dialogue": [
|
||||
{
|
||||
"position": {
|
||||
"x": -0.3071011,
|
||||
"y": 2.741472,
|
||||
"z": -4.005298
|
||||
},
|
||||
"radius": 0,
|
||||
"rename": "WarpDriveDialogue",
|
||||
"xmlFile": "Assets/WarpDriveDialogue.xml",
|
||||
"blockAfterPersistentCondition": "KnowsAboutWarpDrive",
|
||||
"remoteTrigger": {
|
||||
"radius": 1,
|
||||
"position": {
|
||||
"x": -0.05656214,
|
||||
"y": 0.5362684,
|
||||
"z": 0.5467669
|
||||
},
|
||||
"rename": "WarpDriveRemoteTrigger"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,7 @@
|
||||
"Trifid#Tester\n#Programmer",
|
||||
"Nageld#Programmer",
|
||||
"Ernesto#Fish",
|
||||
"With help from#Raicuparta\n#dgarroDC\n#jtsalomo\n#and the modding community",
|
||||
"With help from#Raicuparta\n#dgarroDC\n#jtsalomo\n#coderCleric\n#TRSasasusu\n#and the modding community",
|
||||
" ",
|
||||
"Based off Marshmallow made by#_nebula",
|
||||
"With help from#AmazingAlek\n#Raicuparta\n#and the Outer Wilds discord server",
|
||||
|
||||
Binary file not shown.
@ -1,12 +1,12 @@
|
||||
ManifestFileVersion: 0
|
||||
CRC: 3537427957
|
||||
CRC: 2245901288
|
||||
Hashes:
|
||||
AssetFileHash:
|
||||
serializedVersion: 2
|
||||
Hash: c4d8f41970054074bb375ac5cbe82855
|
||||
Hash: e765e5fc418c1ed69586a3826e0cdea3
|
||||
TypeTreeHash:
|
||||
serializedVersion: 2
|
||||
Hash: de71b9c55befb829b1640ea21774b932
|
||||
Hash: 65942a71d50cdc9f2387a8fa9383a3f8
|
||||
HashAppended: 0
|
||||
ClassTypes:
|
||||
- Class: 1
|
||||
@ -17,6 +17,8 @@ ClassTypes:
|
||||
Script: {instanceID: 0}
|
||||
- Class: 23
|
||||
Script: {instanceID: 0}
|
||||
- Class: 28
|
||||
Script: {instanceID: 0}
|
||||
- Class: 33
|
||||
Script: {instanceID: 0}
|
||||
- Class: 43
|
||||
@ -39,6 +41,8 @@ ClassTypes:
|
||||
Script: {instanceID: 0}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 70edf1000ebf31e4eb3ab4e289a345c0, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 86d5ae109bbc920409997135e88f1755, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 77b727c07614b4041a5fe1fba0cfacff, type: 3}
|
||||
- Class: 114
|
||||
@ -75,6 +79,8 @@ ClassTypes:
|
||||
Script: {fileID: 11500000, guid: 040dd594681f07a4a975890a61d44be5, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 327eb94566c9e284dae5d7b1cfe11ccd, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 8d56b3759dd12424c8425ed62fc02796, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: c317f6a5634f15f4c80f89e306616924, type: 3}
|
||||
- Class: 114
|
||||
@ -97,10 +103,12 @@ ClassTypes:
|
||||
Script: {fileID: 11500000, guid: b4b79e57677045045a95bfe4fe447ce5, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 64247dd7b0c5ac640a6d9ae5360a0f5a, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: f645b92850d716a4488617b651223700, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 8ef66a28deb09ab4aaba30bb60b9f19a, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 0863077874402f14dba0ca4ae81752dd, type: 3}
|
||||
Script: {fileID: 11500000, guid: bf998978a8a701b4eb09fcd94048f916, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: a9da74c8b134add4ba1d884336a5e075, type: 3}
|
||||
- Class: 114
|
||||
@ -171,7 +179,24 @@ ClassTypes:
|
||||
Script: {instanceID: 0}
|
||||
SerializeReferenceClassIdentifiers: []
|
||||
Assets:
|
||||
- Assets/SlideReels/Prefab_DW_Reel_Whole.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Rusted_7.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Destroyed_6.prefab
|
||||
- Assets/SlideReels/Effects_IP_SIM_SlideReel.prefab
|
||||
- Assets/SlideReels/Prefab_DW_Reel_7.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Rusted_6.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Rusted_8.prefab
|
||||
- Assets/SlideReels/Prefab_DW_Reel_6.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_8.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_6.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Destroyed_7.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Destroyed_Whole.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Destroyed_8.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Whole.prefab
|
||||
- Assets/SlideReels/Prefab_IP_Reel_Rusted_Whole.prefab
|
||||
- Assets/BrambleCollision.prefab
|
||||
- Assets/SlideReels/Prefab_DW_Reel_8.prefab
|
||||
- Assets/Vessel_Body.prefab
|
||||
- Assets/AmbientLight_QM.png
|
||||
- Assets/SlideReels/Prefab_IP_Reel_7.prefab
|
||||
Dependencies: []
|
||||
|
||||
BIN
NewHorizons/Assets/textures/blank_slide_reel.png
Normal file
BIN
NewHorizons/Assets/textures/blank_slide_reel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 B |
BIN
NewHorizons/Assets/textures/inverted_blank_slide_reel.png
Normal file
BIN
NewHorizons/Assets/textures/inverted_blank_slide_reel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 B |
@ -1,6 +1,20 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/xen-42/outer-wilds-new-horizons/main/NewHorizons/Schemas/translation_schema.json",
|
||||
"DialogueDictionary": {
|
||||
"NEW_HORIZONS_WARP_DRIVE_DIALOGUE_1": "Twój statek jest teraz wyposażony z napędem warp!",
|
||||
"NEW_HORIZONS_WARP_DRIVE_DIALOGUE_2": "Możesz użyć nowy \"Tryb międzygwiezdny\" w Dzienniku Pokładowym żeby zablokować twój autopilot na inny Układ Gwiazdy.",
|
||||
"NEW_HORIZONS_WARP_DRIVE_DIALOGUE_3": "A potem zapnij pasy i zaangażój wypaczanie!"
|
||||
},
|
||||
"UIDictionary": {
|
||||
"INTERSTELLAR_MODE": "Tryb międzygwiezdny",
|
||||
"FREQ_STATUE": "Statua Nomai",
|
||||
"FREQ_WARP_CORE": "Strumień Anty-Grawitonowy",
|
||||
"FREQ_UNKNOWN": "???",
|
||||
"ENGAGE_WARP_PROMPT": "Zaangażować Wypaczanie do {0}",
|
||||
"WARP_LOCKED": "AUTOPILOT ZABLOKOWANY NA:\n{0}",
|
||||
"LOCK_AUTOPILOT_WARP": "Zablokuj Autopilot na Układ Gwiazdy",
|
||||
"RICH_PRESENCE_EXPLORING": "Eksploruje {0}.",
|
||||
"RICH_PRESENCE_WARPING": "Wypaczanie do {0}.",
|
||||
"Vessel": "Statku"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.External.Modules.Props;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.Files;
|
||||
using OWML.Common;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Builder.Atmosphere
|
||||
{
|
||||
public static class FogBuilder
|
||||
@ -26,7 +26,9 @@ namespace NewHorizons.Builder.Atmosphere
|
||||
|
||||
internal static void InitPrefabs()
|
||||
{
|
||||
if (_ramp == null) _ramp = ImageUtilities.GetTexture(Main.Instance, "Assets/textures/FogColorRamp.png");
|
||||
// Checking null here it was getting destroyed and wouldnt reload and never worked outside of the first loop
|
||||
// GetTexture caches itself anyway so it doesn't matter that this gets called multiple times
|
||||
_ramp = ImageUtilities.GetTexture(Main.Instance, "Assets/textures/FogColorRamp.png");
|
||||
|
||||
if (_isInit) return;
|
||||
|
||||
@ -73,6 +75,7 @@ namespace NewHorizons.Builder.Atmosphere
|
||||
atmo.fogRampPath != null ? ImageUtilities.GetTexture(mod, atmo.fogRampPath) :
|
||||
atmo.fogTint != null ? ImageUtilities.TintImage(_ramp, atmo.fogTint.ToColor()) :
|
||||
_ramp;
|
||||
|
||||
PFC.fogColorRampTexture = colorRampTexture;
|
||||
PFC.fogColorRampIntensity = 1f;
|
||||
if (atmo.fogTint != null)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.External.Modules.VariableSize;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Builder.Atmosphere
|
||||
{
|
||||
public static class SunOverrideBuilder
|
||||
|
||||
@ -36,7 +36,6 @@ namespace NewHorizons.Builder.Body
|
||||
|
||||
config.Base = new BaseModule()
|
||||
{
|
||||
hasMapMarker = false,
|
||||
surfaceGravity = 1,
|
||||
surfaceSize = size,
|
||||
gravityFallOff = GravityFallOff.InverseSquared
|
||||
@ -58,6 +57,11 @@ namespace NewHorizons.Builder.Body
|
||||
enabled = false
|
||||
};
|
||||
|
||||
config.MapMarker = new MapMarkerModule()
|
||||
{
|
||||
enabled = false
|
||||
};
|
||||
|
||||
config.ProcGen = belt.procGen;
|
||||
if (config.ProcGen == null)
|
||||
{
|
||||
|
||||
@ -11,6 +11,8 @@ using NewHorizons.Builder.Props;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using NewHorizons.Utility.OuterWilds;
|
||||
using NewHorizons.External.SerializableData;
|
||||
using NewHorizons.Builder.Volumes;
|
||||
using System;
|
||||
|
||||
namespace NewHorizons.Builder.Body
|
||||
{
|
||||
@ -109,31 +111,52 @@ namespace NewHorizons.Builder.Body
|
||||
{
|
||||
foreach (var pair in _pairsToLink)
|
||||
{
|
||||
var (blackHoleID, whiteHoleID) = pair;
|
||||
if (!_singularitiesByID.TryGetValue(blackHoleID, out GameObject blackHole))
|
||||
try
|
||||
{
|
||||
NHLogger.LogWarning($"Black hole [{blackHoleID}] is missing.");
|
||||
continue;
|
||||
var (blackHoleID, whiteHoleID) = pair;
|
||||
if (!_singularitiesByID.TryGetValue(blackHoleID, out GameObject blackHole))
|
||||
{
|
||||
NHLogger.LogWarning($"Black hole [{blackHoleID}] is missing.");
|
||||
continue;
|
||||
}
|
||||
if (!_singularitiesByID.TryGetValue(whiteHoleID, out GameObject whiteHole))
|
||||
{
|
||||
NHLogger.LogWarning($"White hole [{whiteHoleID}] is missing.");
|
||||
continue;
|
||||
}
|
||||
var whiteHoleVolume = whiteHole.GetComponentInChildren<WhiteHoleVolume>();
|
||||
var blackHoleVolume = blackHole.GetComponentInChildren<BlackHoleVolume>();
|
||||
if (whiteHoleVolume == null || blackHoleVolume == null)
|
||||
{
|
||||
NHLogger.LogWarning($"Singularities [{blackHoleID}] and [{whiteHoleID}] do not have compatible polarities.");
|
||||
continue;
|
||||
}
|
||||
if (blackHoleVolume._whiteHole != null && blackHoleVolume._whiteHole != whiteHoleVolume)
|
||||
{
|
||||
NHLogger.LogWarning($"Black hole [{blackHoleID}] has already been linked!");
|
||||
continue;
|
||||
}
|
||||
NHLogger.LogVerbose($"Pairing singularities [{blackHoleID}], [{whiteHoleID}]");
|
||||
blackHoleVolume._whiteHole = whiteHoleVolume;
|
||||
|
||||
// If warping to a vanilla planet, we add a streaming volume to pre-load it
|
||||
var streamingGroup = whiteHoleVolume.GetAttachedOWRigidbody().GetComponentInChildren<StreamingGroup>();
|
||||
if (streamingGroup != null)
|
||||
{
|
||||
var sphereCollider = blackHoleVolume.GetComponent<SphereCollider>();
|
||||
// Shouldn't ever be null but doesn't hurt ig
|
||||
var loadRadius = sphereCollider == null ? 100f : sphereCollider.radius + 50f;
|
||||
var streamingVolume = VolumeBuilder.Make<StreamingWarpVolume>(blackHoleVolume.GetAttachedOWRigidbody().gameObject, blackHoleVolume.GetComponentInParent<Sector>(),
|
||||
new External.Modules.Volumes.VolumeInfos.VolumeInfo() { radius = loadRadius });
|
||||
streamingVolume.streamingGroup = streamingGroup;
|
||||
streamingVolume.transform.parent = blackHoleVolume.transform;
|
||||
streamingVolume.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
}
|
||||
if (!_singularitiesByID.TryGetValue(whiteHoleID, out GameObject whiteHole))
|
||||
catch (Exception e)
|
||||
{
|
||||
NHLogger.LogWarning($"White hole [{whiteHoleID}] is missing.");
|
||||
continue;
|
||||
NHLogger.LogError($"Failed to pair singularities {e}");
|
||||
}
|
||||
var whiteHoleVolume = whiteHole.GetComponentInChildren<WhiteHoleVolume>();
|
||||
var blackHoleVolume = blackHole.GetComponentInChildren<BlackHoleVolume>();
|
||||
if (whiteHoleVolume == null || blackHoleVolume == null)
|
||||
{
|
||||
NHLogger.LogWarning($"Singularities [{blackHoleID}] and [{whiteHoleID}] do not have compatible polarities.");
|
||||
continue;
|
||||
}
|
||||
if (blackHoleVolume._whiteHole != null && blackHoleVolume._whiteHole != whiteHoleVolume)
|
||||
{
|
||||
NHLogger.LogWarning($"Black hole [{blackHoleID}] has already been linked!");
|
||||
continue;
|
||||
}
|
||||
NHLogger.LogVerbose($"Pairing singularities [{blackHoleID}], [{whiteHoleID}]");
|
||||
blackHoleVolume._whiteHole = whiteHoleVolume;
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,7 +190,7 @@ namespace NewHorizons.Builder.Body
|
||||
|
||||
OWAudioSource oneShotOWAudioSource = null;
|
||||
|
||||
var singularityAmbience = Object.Instantiate(_blackHoleAmbience, singularity.transform);
|
||||
var singularityAmbience = GameObject.Instantiate(_blackHoleAmbience, singularity.transform);
|
||||
singularityAmbience.name = polarity ? "BlackHoleAmbience" : "WhiteHoleAmbience";
|
||||
singularityAmbience.SetActive(true);
|
||||
singularityAmbience.GetComponent<SectorAudioGroup>().SetSector(sector);
|
||||
@ -214,7 +237,7 @@ namespace NewHorizons.Builder.Body
|
||||
}
|
||||
else
|
||||
{
|
||||
var blackHoleOneShot = Object.Instantiate(_blackHoleEmissionOneShot, singularity.transform);
|
||||
var blackHoleOneShot = GameObject.Instantiate(_blackHoleEmissionOneShot, singularity.transform);
|
||||
blackHoleOneShot.name = "BlackHoleEmissionOneShot";
|
||||
blackHoleOneShot.SetActive(true);
|
||||
oneShotOWAudioSource = blackHoleOneShot.GetComponent<OWAudioSource>();
|
||||
@ -223,7 +246,7 @@ namespace NewHorizons.Builder.Body
|
||||
oneShotAudioSource.minDistance = horizon;
|
||||
if (sizeController != null) sizeController.oneShotAudioSource = oneShotAudioSource;
|
||||
|
||||
var blackHoleVolume = Object.Instantiate(_blackHoleVolume, singularity.transform);
|
||||
var blackHoleVolume = GameObject.Instantiate(_blackHoleVolume, singularity.transform);
|
||||
blackHoleVolume.name = "BlackHoleVolume";
|
||||
|
||||
// Scale vanish effect to black hole size
|
||||
@ -249,7 +272,7 @@ namespace NewHorizons.Builder.Body
|
||||
{
|
||||
foreach (var renderer in blackHoleVolume.GetComponentsInChildren<ParticleSystemRenderer>(true))
|
||||
{
|
||||
Object.Destroy(renderer);
|
||||
GameObject.Destroy(renderer);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -257,7 +280,7 @@ namespace NewHorizons.Builder.Body
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject whiteHoleVolumeGO = Object.Instantiate(_whiteHoleVolume);
|
||||
GameObject whiteHoleVolumeGO = GameObject.Instantiate(_whiteHoleVolume);
|
||||
whiteHoleVolumeGO.transform.parent = singularity.transform;
|
||||
whiteHoleVolumeGO.transform.localPosition = Vector3.zero;
|
||||
whiteHoleVolumeGO.transform.localScale = Vector3.one;
|
||||
|
||||
@ -408,10 +408,15 @@ namespace NewHorizons.Builder.Body
|
||||
if (starModule.endTint != null)
|
||||
{
|
||||
var endColour = starModule.endTint.ToColor();
|
||||
darkenedColor = new Color(endColour.r * modifier, endColour.g * modifier, endColour.b * modifier);
|
||||
var adjustedEndColour = new Color(endColour.r * modifier, endColour.g * modifier, endColour.b * modifier);
|
||||
Color.RGBToHSV(adjustedEndColour, out var hEnd, out var sEnd, out var vEnd);
|
||||
var darkenedEndColor = Color.HSVToRGB(hEnd, sEnd * 1.2f, vEnd * 0.1f);
|
||||
surface.sharedMaterial.SetTexture(ColorRamp, ImageUtilities.LerpGreyscaleImageAlongX(_colorOverTime, adjustedColour, darkenedColor, adjustedEndColour, darkenedEndColor));
|
||||
}
|
||||
else
|
||||
{
|
||||
surface.sharedMaterial.SetTexture(ColorRamp, ImageUtilities.LerpGreyscaleImage(_colorOverTime, adjustedColour, darkenedColor));
|
||||
}
|
||||
|
||||
surface.sharedMaterial.SetTexture(ColorRamp, ImageUtilities.LerpGreyscaleImage(_colorOverTime, adjustedColour, darkenedColor));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(starModule.starRampTexture))
|
||||
|
||||
@ -135,7 +135,8 @@ namespace NewHorizons.Builder.Body
|
||||
var fogGO = Object.Instantiate(_oceanFog, waterGO.transform);
|
||||
fogGO.name = "OceanFog";
|
||||
fogGO.transform.localPosition = Vector3.zero;
|
||||
fogGO.transform.localScale = Vector3.one;
|
||||
// In base game GD ocean fog is 550 while the water volume is 500
|
||||
fogGO.transform.localScale = Vector3.one * 550f / 500f;
|
||||
fogGO.SetActive(true);
|
||||
|
||||
if (module.tint != null)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
using NewHorizons.Components;
|
||||
using NewHorizons.Components.Orbital;
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.External;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using UnityEngine;
|
||||
|
||||
@ -8,11 +8,15 @@ namespace NewHorizons.Builder.General
|
||||
{
|
||||
public static class AstroObjectBuilder
|
||||
{
|
||||
public static NHAstroObject Make(GameObject body, AstroObject primaryBody, PlanetConfig config, bool isVanilla)
|
||||
public static NHAstroObject Make(GameObject body, AstroObject primaryBody, NewHorizonsBody nhBody, bool isVanilla)
|
||||
{
|
||||
NHAstroObject astroObject = body.AddComponent<NHAstroObject>();
|
||||
astroObject.modUniqueName = nhBody.Mod.ModHelper.Manifest.UniqueName;
|
||||
|
||||
var config = nhBody.Config;
|
||||
|
||||
astroObject.isVanilla = isVanilla;
|
||||
astroObject.HideDisplayName = !config.Base.hasMapMarker;
|
||||
astroObject.HideDisplayName = !config.MapMarker.enabled;
|
||||
astroObject.invulnerableToSun = config.Base.invulnerableToSun;
|
||||
|
||||
if (config.Orbit != null) astroObject.SetOrbitalParametersFromConfig(config.Orbit);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#region
|
||||
#region
|
||||
|
||||
using NewHorizons.Components;
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.Handlers;
|
||||
using UnityEngine;
|
||||
@ -12,7 +13,8 @@ namespace NewHorizons.Builder.General
|
||||
{
|
||||
public static void Make(GameObject body, string name, PlanetConfig config)
|
||||
{
|
||||
MapMarker mapMarker = body.AddComponent<MapMarker>();
|
||||
var module = config.MapMarker;
|
||||
NHMapMarker mapMarker = body.AddComponent<NHMapMarker>();
|
||||
mapMarker._labelID = (UITextType)TranslationHandler.AddUI(config.name);
|
||||
|
||||
var markerType = MapMarker.MarkerType.Planet;
|
||||
@ -37,6 +39,9 @@ namespace NewHorizons.Builder.General
|
||||
*/
|
||||
|
||||
mapMarker._markerType = markerType;
|
||||
|
||||
mapMarker.minDisplayDistanceOverride = module.minDisplayDistanceOverride;
|
||||
mapMarker.maxDisplayDistanceOverride = module.maxDisplayDistanceOverride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,8 @@ namespace NewHorizons.Builder.General
|
||||
{
|
||||
// We can't not build a reference frame volume, Cloak requires one to be there
|
||||
module.maxTargetDistance = 0f;
|
||||
module.targetWhenClose = true;
|
||||
module.targetColliderRadius = 0.001f;
|
||||
module.hideInMap = true;
|
||||
owrb.SetIsTargetable(false);
|
||||
}
|
||||
|
||||
@ -11,8 +11,8 @@ namespace NewHorizons.Builder.General
|
||||
{
|
||||
var sectorGO = new GameObject("Sector");
|
||||
sectorGO.SetActive(false);
|
||||
sectorGO.transform.parent = planetBody.transform;
|
||||
sectorGO.transform.localPosition = Vector3.zero;
|
||||
// Have to use set parent method without keeping world position to Fix sectors being rotated on tidally locked bodies #870
|
||||
sectorGO.transform.SetParent(planetBody.transform, false);
|
||||
|
||||
var SS = sectorGO.AddComponent<SphereShape>();
|
||||
SS.SetCollisionMode(Shape.CollisionMode.Volume);
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
using HarmonyLib;
|
||||
using NewHorizons.External;
|
||||
using NewHorizons.External.Modules.Props.Audio;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
using OWML.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
@ -36,27 +38,16 @@ namespace NewHorizons.Builder.Props.Audio
|
||||
};
|
||||
NumberOfFrequencies = EnumUtils.GetValues<SignalFrequency>().Length;
|
||||
|
||||
_qmSignals = new (){ SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent<AudioSignal>() };
|
||||
_qmSignals = new () { SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent<AudioSignal>() };
|
||||
_cloakedSignals = new();
|
||||
|
||||
Initialized = true;
|
||||
|
||||
SceneManager.sceneUnloaded -= OnSceneUnloaded;
|
||||
SceneManager.sceneUnloaded += OnSceneUnloaded;
|
||||
Main.Instance.OnStarSystemLoaded.RemoveListener(OnStarSystemLoaded);
|
||||
Main.Instance.OnStarSystemLoaded.AddListener(OnStarSystemLoaded);
|
||||
}
|
||||
|
||||
private static HashSet<SignalFrequency> _frequenciesInUse = new();
|
||||
|
||||
private static void OnSceneUnloaded(Scene _)
|
||||
{
|
||||
_frequenciesInUse.Clear();
|
||||
}
|
||||
|
||||
private static void OnStarSystemLoaded(string starSystem)
|
||||
{
|
||||
// If its the base game solar system or eye we get all the main frequencies
|
||||
var starSystem = Main.Instance.CurrentStarSystem;
|
||||
if (starSystem == "SolarSystem" || starSystem == "EyeOfTheUniverse")
|
||||
{
|
||||
_frequenciesInUse.Add(SignalFrequency.Quantum);
|
||||
@ -69,19 +60,43 @@ namespace NewHorizons.Builder.Props.Audio
|
||||
// We don't want a scenario where the player knows no frequencies
|
||||
_frequenciesInUse.Add(SignalFrequency.Traveler);
|
||||
|
||||
// Make sure the NH save file has all the right frequencies
|
||||
// Skip "default"
|
||||
for (int i = 1; i < PlayerData._currentGameSave.knownFrequencies.Length; i++)
|
||||
{
|
||||
if (PlayerData._currentGameSave.knownFrequencies[i])
|
||||
{
|
||||
NewHorizonsData.LearnFrequency(AudioSignal.IndexToFrequency(i).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
NHLogger.LogVerbose($"Frequencies in use in {starSystem}: {_frequenciesInUse.Join(x => x.ToString())}");
|
||||
}
|
||||
|
||||
private static HashSet<SignalFrequency> _frequenciesInUse = new();
|
||||
|
||||
private static void OnSceneUnloaded(Scene _)
|
||||
{
|
||||
_frequenciesInUse.Clear();
|
||||
}
|
||||
|
||||
public static bool IsFrequencyInUse(SignalFrequency freq) => _frequenciesInUse.Contains(freq);
|
||||
|
||||
public static bool IsFrequencyInUse(string freqString)
|
||||
{
|
||||
if (Enum.TryParse<SignalFrequency>(freqString, out var freq))
|
||||
{
|
||||
return IsFrequencyInUse(freq);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsCloaked(this AudioSignal signal) => _cloakedSignals.Contains(signal);
|
||||
|
||||
public static bool IsOnQuantumMoon(this AudioSignal signal) => _qmSignals.Contains(signal);
|
||||
|
||||
public static SignalFrequency AddFrequency(string str)
|
||||
{
|
||||
if (_customFrequencyNames == null) Init();
|
||||
|
||||
var freq = CollectionUtilities.KeyByValue(_customFrequencyNames, str);
|
||||
if (freq != default) return freq;
|
||||
|
||||
@ -99,23 +114,20 @@ namespace NewHorizons.Builder.Props.Audio
|
||||
NumberOfFrequencies = EnumUtils.GetValues<SignalFrequency>().Length;
|
||||
|
||||
// This stuff happens after the signalscope is Awake so we have to change the number of frequencies now
|
||||
Object.FindObjectOfType<Signalscope>()._strongestSignals = new AudioSignal[NumberOfFrequencies + 1];
|
||||
GameObject.FindObjectOfType<Signalscope>()._strongestSignals = new AudioSignal[NumberOfFrequencies + 1];
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
public static string GetCustomFrequencyName(SignalFrequency frequencyName)
|
||||
{
|
||||
if (_customFrequencyNames == null) Init();
|
||||
|
||||
if (_customFrequencyNames == null) return string.Empty;
|
||||
_customFrequencyNames.TryGetValue(frequencyName, out string name);
|
||||
return name;
|
||||
}
|
||||
|
||||
public static SignalName AddSignalName(string str)
|
||||
{
|
||||
if (_customSignalNames == null) Init();
|
||||
|
||||
var name = CollectionUtilities.KeyByValue(_customSignalNames, str);
|
||||
if (name != default) return name;
|
||||
|
||||
@ -129,8 +141,7 @@ namespace NewHorizons.Builder.Props.Audio
|
||||
|
||||
public static string GetCustomSignalName(SignalName signalName)
|
||||
{
|
||||
if (_customSignalNames == null) Init();
|
||||
|
||||
if (_customSignalNames == null) return string.Empty;
|
||||
_customSignalNames.TryGetValue(signalName, out string name);
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ using NewHorizons.Handlers;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.OuterWilds;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using Newtonsoft.Json;
|
||||
using OWML.Common;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -33,12 +34,17 @@ namespace NewHorizons.Builder.Props
|
||||
private static GameObject _brambleSeedPrefab;
|
||||
private static GameObject _brambleNodePrefab;
|
||||
|
||||
private static HashSet<FogWarpVolume> _nhFogWarpVolumes = new();
|
||||
|
||||
public static bool IsNHFogWarpVolume(FogWarpVolume volume) => _nhFogWarpVolumes.Contains(volume);
|
||||
|
||||
public static void Init(PlanetConfig[] dimensionConfigs)
|
||||
{
|
||||
_unpairedNodes.Clear();
|
||||
_propagatedSignals.Clear();
|
||||
namedNodes.Clear();
|
||||
builtBrambleNodes.Clear();
|
||||
_nhFogWarpVolumes.Clear();
|
||||
|
||||
PropagateSignals(dimensionConfigs);
|
||||
}
|
||||
@ -107,6 +113,10 @@ namespace NewHorizons.Builder.Props
|
||||
if (dimension.Bramble.nodes == null) continue;
|
||||
foreach (var node in dimension.Bramble.nodes)
|
||||
{
|
||||
if (!dimensionNameToIndex.ContainsKey(node.linksTo))
|
||||
{
|
||||
NHLogger.LogError($"There is no bramble dimension named {node.linksTo}");
|
||||
}
|
||||
var destinationDimensionIndex = dimensionNameToIndex[node.linksTo];
|
||||
access[dimensionIndex, destinationDimensionIndex] = true;
|
||||
}
|
||||
@ -190,6 +200,12 @@ namespace NewHorizons.Builder.Props
|
||||
collider.enabled = true;
|
||||
}
|
||||
|
||||
// We track all the fog warp volumes that NH created so we can only effect those in patches, this way we leave base game stuff alone.
|
||||
foreach (var fogWarpVolume in brambleNode.GetComponentsInChildren<FogWarpVolume>(true).Append(brambleNode.GetComponent<FogWarpVolume>()))
|
||||
{
|
||||
_nhFogWarpVolumes.Add(fogWarpVolume);
|
||||
}
|
||||
|
||||
var innerFogWarpVolume = brambleNode.GetComponent<InnerFogWarpVolume>();
|
||||
var outerFogWarpVolume = GetOuterFogWarpVolumeFromAstroObject(go);
|
||||
var fogLight = brambleNode.GetComponent<FogLight>();
|
||||
@ -239,6 +255,12 @@ namespace NewHorizons.Builder.Props
|
||||
foreach(Transform child in brambleNode.transform)
|
||||
{
|
||||
child.localScale = Vector3.one * config.scale;
|
||||
|
||||
// The fog on bramble seeds has a specific scale we need to copy over
|
||||
if (child.name == "VolumetricFogSphere (2)")
|
||||
{
|
||||
child.localScale *= 6.3809f;
|
||||
}
|
||||
}
|
||||
innerFogWarpVolume._warpRadius *= config.scale;
|
||||
innerFogWarpVolume._exitRadius *= config.scale;
|
||||
@ -397,7 +419,13 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
foreach (var signalConfig in connectedSignals)
|
||||
{
|
||||
var signalGO = SignalBuilder.Make(go, sector, signalConfig, mod);
|
||||
// Have to ensure that this new signal doesn't use parent path, else it looks for a parent that only exists on the original body
|
||||
// Have to make a copy of it as well to avoid modifying the old body's info
|
||||
var signalConfigCopy = JsonConvert.DeserializeObject<SignalInfo>(JsonConvert.SerializeObject(signalConfig));
|
||||
signalConfigCopy.parentPath = null;
|
||||
signalConfigCopy.isRelativeToParent = false;
|
||||
|
||||
var signalGO = SignalBuilder.Make(go, sector, signalConfigCopy, mod);
|
||||
signalGO.GetComponent<AudioSignal>()._identificationDistance = 0;
|
||||
signalGO.GetComponent<AudioSignal>()._sourceRadius = 1;
|
||||
signalGO.transform.position = brambleNode.transform.position;
|
||||
|
||||
@ -101,6 +101,7 @@ namespace NewHorizons.Builder.Props
|
||||
GameObject prop;
|
||||
bool isItem;
|
||||
bool invalidComponentFound = false;
|
||||
bool isFromAssetBundle = !string.IsNullOrEmpty(detail.assetBundle);
|
||||
|
||||
// We save copies with all their components fixed, good if the user is placing the same detail more than once
|
||||
if (detail?.path != null && _fixedPrefabCache.TryGetValue((sector, detail.path), out var storedPrefab))
|
||||
@ -139,7 +140,29 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
else
|
||||
{
|
||||
FixSectoredComponent(component, sector, existingSectors, detail.keepLoaded);
|
||||
// Fix cull groups only when not from an asset bundle (because then they're there on purpose!)
|
||||
// keepLoaded should remove existing groups
|
||||
// renderers/colliders get enabled later so we dont have to do that here
|
||||
if (detail.keepLoaded && !isFromAssetBundle && component is SectorCullGroup or SectorCollisionGroup or SectorLightsCullGroup)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(component);
|
||||
continue;
|
||||
}
|
||||
|
||||
FixSectoredComponent(component, sector, existingSectors);
|
||||
}
|
||||
|
||||
// Asset bundle is a real string -> Object loaded from unity
|
||||
// If they're adding dialogue we have to manually register the xml text
|
||||
if (isFromAssetBundle && component is CharacterDialogueTree dialogue)
|
||||
{
|
||||
DialogueBuilder.HandleUnityCreatedDialogue(dialogue);
|
||||
}
|
||||
|
||||
// copied details need their lanterns fixed
|
||||
if (!isFromAssetBundle && component is DreamLanternController lantern)
|
||||
{
|
||||
lantern.gameObject.AddComponent<DreamLanternControllerFixer>();
|
||||
}
|
||||
|
||||
FixComponent(component, go, detail.ignoreSun);
|
||||
@ -171,6 +194,11 @@ namespace NewHorizons.Builder.Props
|
||||
if (detail.item != null)
|
||||
{
|
||||
ItemBuilder.MakeItem(prop, go, sector, detail.item, mod);
|
||||
isItem = true;
|
||||
if (detail.hasPhysics)
|
||||
{
|
||||
NHLogger.LogWarning($"An item with the path {detail.path} has both '{nameof(DetailInfo.hasPhysics)}' and '{nameof(DetailInfo.item)}' set. This will usually result in undesirable behavior.");
|
||||
}
|
||||
}
|
||||
|
||||
if (detail.itemSocket != null)
|
||||
@ -266,16 +294,8 @@ namespace NewHorizons.Builder.Props
|
||||
/// <summary>
|
||||
/// Fix components that have sectors. Has a specific fix if there is a VisionTorchItem on the object.
|
||||
/// </summary>
|
||||
private static void FixSectoredComponent(Component component, Sector sector, HashSet<Sector> existingSectors, bool keepLoaded)
|
||||
private static void FixSectoredComponent(Component component, Sector sector, HashSet<Sector> existingSectors)
|
||||
{
|
||||
// keepLoaded should remove existing groups
|
||||
// renderers/colliders get enabled later so we dont have to do that here
|
||||
if (keepLoaded && component is SectorCullGroup or SectorCollisionGroup or SectorLightsCullGroup)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(component);
|
||||
return;
|
||||
}
|
||||
|
||||
// fix Sector stuff, eg SectorCullGroup (without this, props that have a SectorCullGroup component will become invisible inappropriately)
|
||||
if (component is ISectorGroup sectorGroup && !existingSectors.Contains(sectorGroup.GetSector()))
|
||||
{
|
||||
@ -283,26 +303,8 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
|
||||
// Not doing else if here because idk if any of the classes below implement ISectorGroup
|
||||
|
||||
// Null check else shuttles controls break
|
||||
// parent sector is always null before Awake so this code actually never runs lol
|
||||
if (component is Sector s && s.GetParentSector() != null && !existingSectors.Contains(s.GetParentSector()))
|
||||
{
|
||||
s.SetParentSector(sector);
|
||||
}
|
||||
|
||||
else if (component is SectorCullGroup sectorCullGroup)
|
||||
{
|
||||
sectorCullGroup._controllingProxy = null;
|
||||
|
||||
// fixes sector cull group deactivating renderers on map view enter and fast foward
|
||||
// TODO: does this actually work? what? how?
|
||||
sectorCullGroup._inMapView = false;
|
||||
sectorCullGroup._isFastForwarding = false;
|
||||
sectorCullGroup.SetVisible(sectorCullGroup.ShouldBeVisible(), true, false);
|
||||
}
|
||||
|
||||
else if(component is SectoredMonoBehaviour behaviour && !existingSectors.Contains(behaviour._sector))
|
||||
if(component is SectoredMonoBehaviour behaviour && !existingSectors.Contains(behaviour._sector))
|
||||
{
|
||||
// not using SetSector here because it registers the events twice
|
||||
// perhaps this happens with ISectorGroup.SetSector or Sector.SetParentSector too? idk and nothing seems to break because of it yet
|
||||
@ -421,6 +423,11 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
component.gameObject.AddComponent<AnglerAnimFixer>();
|
||||
}
|
||||
// Add custom logic to NH-spawned rafts to handle fluid changes
|
||||
else if (component is RaftController raft)
|
||||
{
|
||||
component.gameObject.AddComponent<NHRaftController>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -437,7 +444,7 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
NHLogger.LogVerbose("Fixing anglerfish animation");
|
||||
|
||||
// Remove any event reference to its angler
|
||||
// Remove any event reference to its angler so that they dont change its state
|
||||
if (angler._anglerfishController)
|
||||
{
|
||||
angler._anglerfishController.OnChangeAnglerState -= angler.OnChangeAnglerState;
|
||||
@ -445,7 +452,8 @@ namespace NewHorizons.Builder.Props
|
||||
angler._anglerfishController.OnAnglerSuspended -= angler.OnAnglerSuspended;
|
||||
angler._anglerfishController.OnAnglerUnsuspended -= angler.OnAnglerUnsuspended;
|
||||
}
|
||||
angler.enabled = true;
|
||||
// Disable the angler anim controller because we don't want Update or LateUpdate to run, just need it to set the initial Animator state
|
||||
angler.enabled = false;
|
||||
angler.OnChangeAnglerState(AnglerfishController.AnglerState.Lurking);
|
||||
|
||||
Destroy(this);
|
||||
@ -499,5 +507,53 @@ namespace NewHorizons.Builder.Props
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// need component here to run after DreamLanternController.Awake
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(DreamLanternController))]
|
||||
private class DreamLanternControllerFixer : MonoBehaviour
|
||||
{
|
||||
private void Start()
|
||||
{
|
||||
// based on https://github.com/Bwc9876/OW-Amogus/blob/master/Amogus/LanternCreator.cs
|
||||
// needed to fix petals looking backwards, among other things
|
||||
|
||||
var lantern = GetComponent<DreamLanternController>();
|
||||
|
||||
// this is set in Awake, we wanna override it
|
||||
|
||||
// Manually copied these values from a artifact lantern so that we don't have to find it (works in Eye)
|
||||
lantern._origLensFlareBrightness = 0f;
|
||||
lantern._focuserPetalsBaseEulerAngles = new Vector3[]
|
||||
{
|
||||
new Vector3(0.7f, 270.0f, 357.5f),
|
||||
new Vector3(288.7f, 270.1f, 357.4f),
|
||||
new Vector3(323.3f, 90.0f, 177.5f),
|
||||
new Vector3(35.3f, 90.0f, 177.5f),
|
||||
new Vector3(72.7f, 270.1f, 357.5f)
|
||||
};
|
||||
lantern._dirtyFlag_focus = true;
|
||||
lantern._concealerRootsBaseScale = new Vector3[]
|
||||
{
|
||||
Vector3.one,
|
||||
Vector3.one,
|
||||
Vector3.one
|
||||
};
|
||||
lantern._concealerCoversStartPos = new Vector3[]
|
||||
{
|
||||
new Vector3(0.0f, 0.0f, 0.0f),
|
||||
new Vector3(0.0f, -0.1f, 0.0f),
|
||||
new Vector3(0.0f, -0.2f, 0.0f),
|
||||
new Vector3(0.0f, 0.2f, 0.0f),
|
||||
new Vector3(0.0f, 0.1f, 0.0f),
|
||||
new Vector3(0.0f, 0.0f, 0.0f)
|
||||
};
|
||||
lantern._dirtyFlag_concealment = true;
|
||||
lantern.UpdateVisuals();
|
||||
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,15 @@ using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.OuterWilds;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlTypes;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR;
|
||||
|
||||
namespace NewHorizons.Builder.Props
|
||||
{
|
||||
@ -25,6 +30,18 @@ namespace NewHorizons.Builder.Props
|
||||
// Create dialogue directly from xml string instead of loading it from a file
|
||||
public static (CharacterDialogueTree, RemoteDialogueTrigger) Make(GameObject go, Sector sector, DialogueInfo info, string xml, string dialogueName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(info.pathToExistingDialogue))
|
||||
{
|
||||
return MakeNewDialogue(go, sector, info, xml, dialogueName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (AddToExistingDialogue(go, sector, info, xml, dialogueName), null);
|
||||
}
|
||||
}
|
||||
|
||||
private static (CharacterDialogueTree, RemoteDialogueTrigger) MakeNewDialogue(GameObject go, Sector sector, DialogueInfo info, string xml, string dialogueName)
|
||||
{
|
||||
NHLogger.LogVerbose($"[DIALOGUE] Created a new character dialogue [{info.rename}] on [{info.parentPath}]");
|
||||
|
||||
// In stock I think they disable dialogue stuff with conditions
|
||||
@ -36,6 +53,8 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
|
||||
var dialogue = MakeConversationZone(go, sector, info, xml, dialogueName);
|
||||
|
||||
MakeAttentionPoints(go, sector, dialogue, info);
|
||||
|
||||
RemoteDialogueTrigger remoteTrigger = null;
|
||||
if (info.remoteTrigger != null)
|
||||
@ -54,6 +73,177 @@ namespace NewHorizons.Builder.Props
|
||||
return (dialogue, remoteTrigger);
|
||||
}
|
||||
|
||||
private static CharacterDialogueTree AddToExistingDialogue(GameObject go, Sector sector, DialogueInfo info, string xml, string dialogueName)
|
||||
{
|
||||
var dialogueObject = go.FindChild(info.pathToExistingDialogue);
|
||||
if (dialogueObject == null) dialogueObject = SearchUtilities.Find(info.pathToExistingDialogue);
|
||||
var existingDialogue = dialogueObject != null ? dialogueObject.GetComponent<CharacterDialogueTree>() : null;
|
||||
|
||||
if (existingDialogue == null)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't find dialogue at {info.pathToExistingDialogue}!");
|
||||
return null;
|
||||
}
|
||||
|
||||
var existingAsset = existingDialogue._xmlCharacterDialogueAsset;
|
||||
if (existingAsset == null)
|
||||
{
|
||||
var dialogueDoc = new XmlDocument();
|
||||
dialogueDoc.LoadXml(xml);
|
||||
var xmlNode = dialogueDoc.SelectSingleNode("DialogueTree");
|
||||
AddTranslation(xmlNode);
|
||||
|
||||
xml = xmlNode.OuterXml;
|
||||
|
||||
var text = new TextAsset(xml)
|
||||
{
|
||||
// Text assets need a name to be used with VoiceMod
|
||||
name = dialogueName
|
||||
};
|
||||
existingDialogue.SetTextXml(text);
|
||||
|
||||
FixDialogueNextFrame(existingDialogue);
|
||||
|
||||
return existingDialogue;
|
||||
}
|
||||
|
||||
var existingText = existingAsset.text;
|
||||
|
||||
var existingDialogueDoc = new XmlDocument();
|
||||
existingDialogueDoc.LoadXml(existingText);
|
||||
var existingDialogueTree = existingDialogueDoc.DocumentElement.SelectSingleNode("//DialogueTree");
|
||||
|
||||
var existingDialogueNodesByName = new Dictionary<string, XmlNode>();
|
||||
foreach (XmlNode existingDialogueNode in existingDialogueTree.GetChildNodes("DialogueNode"))
|
||||
{
|
||||
var name = existingDialogueNode.GetChildNode("Name").InnerText;
|
||||
existingDialogueNodesByName[name] = existingDialogueNode;
|
||||
}
|
||||
|
||||
var additionalDialogueDoc = new XmlDocument();
|
||||
additionalDialogueDoc.LoadXml(xml);
|
||||
var newDialogueNodes = additionalDialogueDoc.DocumentElement.SelectSingleNode("//DialogueTree").GetChildNodes("DialogueNode");
|
||||
|
||||
foreach (XmlNode newDialogueNode in newDialogueNodes)
|
||||
{
|
||||
var name = newDialogueNode.GetChildNode("Name").InnerText;
|
||||
|
||||
if (existingDialogueNodesByName.TryGetValue(name, out var existingNode))
|
||||
{
|
||||
// We just have to merge the dialogue options
|
||||
var dialogueOptions = newDialogueNode.GetChildNode("DialogueOptionsList").GetChildNodes("DialogueOption");
|
||||
var existingDialogueOptionsList = existingNode.GetChildNode("DialogueOptionsList");
|
||||
if (existingDialogueOptionsList == null)
|
||||
{
|
||||
existingDialogueOptionsList = existingDialogueDoc.CreateElement("DialogueOptionsList");
|
||||
existingNode.AppendChild(existingDialogueOptionsList);
|
||||
}
|
||||
foreach (XmlNode node in dialogueOptions)
|
||||
{
|
||||
var importedNode = existingDialogueOptionsList.OwnerDocument.ImportNode(node, true);
|
||||
// We add them to the start because normally the last option is to return to menu or exit
|
||||
existingDialogueOptionsList.PrependChild(importedNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We add the new dialogue node to the existing dialogue
|
||||
var importedNode = existingDialogueTree.OwnerDocument.ImportNode(newDialogueNode, true);
|
||||
existingDialogueTree.AppendChild(importedNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Character name is required for adding translations, something to do with how OW prefixes its dialogue
|
||||
var characterName = existingDialogueTree.SelectSingleNode("NameField").InnerText;
|
||||
AddTranslation(additionalDialogueDoc.GetChildNode("DialogueTree"), characterName);
|
||||
|
||||
var newTextAsset = new TextAsset(existingDialogueDoc.OuterXml)
|
||||
{
|
||||
name = existingDialogue._xmlCharacterDialogueAsset.name
|
||||
};
|
||||
|
||||
existingDialogue.SetTextXml(newTextAsset);
|
||||
|
||||
FixDialogueNextFrame(existingDialogue);
|
||||
|
||||
MakeAttentionPoints(go, sector, existingDialogue, info);
|
||||
|
||||
return existingDialogue;
|
||||
}
|
||||
|
||||
private static void FixDialogueNextFrame(CharacterDialogueTree characterDialogueTree)
|
||||
{
|
||||
Delay.FireOnNextUpdate(() =>
|
||||
{
|
||||
var rawText = characterDialogueTree._xmlCharacterDialogueAsset.text;
|
||||
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(rawText);
|
||||
var dialogueTree = doc.DocumentElement.SelectSingleNode("//DialogueTree");
|
||||
|
||||
DoDialogueOptionsListReplacement(dialogueTree);
|
||||
|
||||
var newTextAsset = new TextAsset(doc.OuterXml)
|
||||
{
|
||||
name = characterDialogueTree._xmlCharacterDialogueAsset.name
|
||||
};
|
||||
|
||||
characterDialogueTree.SetTextXml(newTextAsset);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Always call this after adding translations, else it won't update them properly
|
||||
/// </summary>
|
||||
/// <param name="dialogueTree"></param>
|
||||
private static void DoDialogueOptionsListReplacement(XmlNode dialogueTree)
|
||||
{
|
||||
var optionsListsByName = new Dictionary<string, XmlNode>();
|
||||
var dialogueNodes = dialogueTree.GetChildNodes("DialogueNode");
|
||||
foreach (XmlNode dialogueNode in dialogueNodes)
|
||||
{
|
||||
var optionsList = dialogueNode.GetChildNode("DialogueOptionsList");
|
||||
if (optionsList != null)
|
||||
{
|
||||
var name = dialogueNode.GetChildNode("Name").InnerText;
|
||||
optionsListsByName[name] = optionsList;
|
||||
}
|
||||
}
|
||||
foreach (var (name, optionsList) in optionsListsByName)
|
||||
{
|
||||
var replacement = optionsList.GetChildNode("ReuseDialogueOptionsListFrom");
|
||||
if (replacement != null)
|
||||
{
|
||||
var replacementName = replacement.InnerText;
|
||||
if (optionsListsByName.TryGetValue(replacementName, out var replacementOptionsList))
|
||||
{
|
||||
if (replacementOptionsList.GetChildNode("ReuseDialogueOptionsListFrom") != null)
|
||||
{
|
||||
NHLogger.LogError($"Can not target a node with ReuseDialogueOptionsListFrom that also reuses options when making dialogue. Node {name} cannot reuse the list from {replacement.InnerText}");
|
||||
}
|
||||
var dialogueNode = optionsList.ParentNode;
|
||||
dialogueNode.RemoveChild(optionsList);
|
||||
dialogueNode.AppendChild(replacementOptionsList.Clone());
|
||||
|
||||
// Have to manually fix the translations here
|
||||
var characterName = dialogueTree.SelectSingleNode("NameField").InnerText;
|
||||
|
||||
var xmlText = replacementOptionsList.SelectNodes("DialogueOption/Text");
|
||||
foreach (object option in xmlText)
|
||||
{
|
||||
var optionData = (XmlNode)option;
|
||||
var text = optionData.InnerText.Trim();
|
||||
TranslationHandler.ReuseDialogueTranslation(text, new string[] { characterName, replacementName }, new string[] { characterName, name });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogError($"Could not reuse dialogue options list from node with Name {replacement.InnerText} to node with Name {name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static RemoteDialogueTrigger MakeRemoteDialogueTrigger(GameObject planetGO, Sector sector, DialogueInfo info, CharacterDialogueTree dialogue)
|
||||
{
|
||||
var conversationTrigger = GeneralPropBuilder.MakeNew("ConversationTrigger", planetGO, sector, info.remoteTrigger, defaultPosition: info.position, defaultParentPath: info.pathToAnimController);
|
||||
@ -109,13 +299,19 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
var dialogueTree = conversationZone.AddComponent<NHCharacterDialogueTree>();
|
||||
|
||||
var dialogueDoc = new XmlDocument();
|
||||
dialogueDoc.LoadXml(xml);
|
||||
var xmlNode = dialogueDoc.SelectSingleNode("DialogueTree");
|
||||
AddTranslation(xmlNode);
|
||||
|
||||
xml = xmlNode.OuterXml;
|
||||
|
||||
var text = new TextAsset(xml)
|
||||
{
|
||||
// Text assets need a name to be used with VoiceMod
|
||||
name = dialogueName
|
||||
};
|
||||
dialogueTree.SetTextXml(text);
|
||||
AddTranslation(xml);
|
||||
|
||||
switch (info.flashlightToggle)
|
||||
{
|
||||
@ -136,9 +332,37 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
conversationZone.SetActive(true);
|
||||
|
||||
FixDialogueNextFrame(dialogueTree);
|
||||
|
||||
return dialogueTree;
|
||||
}
|
||||
|
||||
private static void MakeAttentionPoints(GameObject go, Sector sector, CharacterDialogueTree dialogue, DialogueInfo info)
|
||||
{
|
||||
if (info.attentionPoint != null)
|
||||
{
|
||||
var ptGo = GeneralPropBuilder.MakeNew("AttentionPoint", go, sector, info.attentionPoint, defaultParent: dialogue.transform);
|
||||
dialogue._attentionPoint = ptGo.transform;
|
||||
dialogue._attentionPointOffset = info.attentionPoint.offset;
|
||||
ptGo.SetActive(true);
|
||||
}
|
||||
if (info.swappedAttentionPoints != null && info.swappedAttentionPoints.Length > 0)
|
||||
{
|
||||
foreach (var pointInfo in info.swappedAttentionPoints)
|
||||
{
|
||||
var ptGo = GeneralPropBuilder.MakeNew($"AttentionPoint_{pointInfo.dialogueNode}_{pointInfo.dialoguePage}", go, sector, pointInfo, defaultParent: dialogue.transform);
|
||||
var swapper = ptGo.AddComponent<DialogueAttentionPointSwapper>();
|
||||
swapper._dialogueTree = dialogue;
|
||||
swapper._attentionPoint = ptGo.transform;
|
||||
swapper._attentionPointOffset = pointInfo.offset;
|
||||
swapper._nodeName = pointInfo.dialogueNode;
|
||||
swapper._dialoguePage = pointInfo.dialoguePage;
|
||||
swapper._lookEasing = pointInfo.lookEasing;
|
||||
ptGo.SetActive(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void MakePlayerTrackingZone(GameObject go, CharacterDialogueTree dialogue, DialogueInfo info)
|
||||
{
|
||||
var character = go.transform.Find(info.pathToAnimController);
|
||||
@ -300,14 +524,26 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddTranslation(string xml)
|
||||
[Obsolete("Pass in the DialogueTree XmlNode instead, this is still here because Pikpik was using it in EOTP")]
|
||||
public static void AddTranslation(string xml, string characterName = null)
|
||||
{
|
||||
var xmlDocument = new XmlDocument();
|
||||
xmlDocument.LoadXml(xml);
|
||||
var xmlNode = xmlDocument.SelectSingleNode("DialogueTree");
|
||||
AddTranslation(xmlNode, characterName);
|
||||
}
|
||||
|
||||
public static void AddTranslation(XmlNode xmlNode, string characterName = null)
|
||||
{
|
||||
var xmlNodeList = xmlNode.SelectNodes("DialogueNode");
|
||||
string characterName = xmlNode.SelectSingleNode("NameField").InnerText;
|
||||
TranslationHandler.AddDialogue(characterName);
|
||||
|
||||
// When adding dialogue to existing stuff, we have to pass in the character name
|
||||
// Otherwise we translate it if its from a new dialogue object
|
||||
if (characterName == null)
|
||||
{
|
||||
characterName = xmlNode.SelectSingleNode("NameField").InnerText;
|
||||
TranslationHandler.AddDialogue(characterName);
|
||||
}
|
||||
|
||||
foreach (object obj in xmlNodeList)
|
||||
{
|
||||
@ -333,5 +569,23 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleUnityCreatedDialogue(CharacterDialogueTree dialogue)
|
||||
{
|
||||
var asset = dialogue._xmlCharacterDialogueAsset;
|
||||
if (asset == null) return;
|
||||
var text = asset.text;
|
||||
var dialogueDoc = new XmlDocument();
|
||||
dialogueDoc.LoadXml(text);
|
||||
var xmlNode = dialogueDoc.SelectSingleNode("DialogueTree");
|
||||
AddTranslation(xmlNode, null);
|
||||
var newTextAsset = new TextAsset(dialogueDoc.OuterXml)
|
||||
{
|
||||
name = asset.name
|
||||
};
|
||||
dialogue.SetTextXml(newTextAsset);
|
||||
|
||||
FixDialogueNextFrame(dialogue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +51,10 @@ namespace NewHorizons.Builder.Props
|
||||
item.DisplayName = itemName;
|
||||
item.ItemType = itemType;
|
||||
item.Droppable = info.droppable;
|
||||
item.HoldOffset = info.holdOffset ?? Vector3.zero;
|
||||
item.HoldRotation = info.holdRotation ?? Vector3.zero;
|
||||
item.SocketOffset = info.socketOffset ?? Vector3.zero;
|
||||
item.SocketRotation = info.socketRotation ?? Vector3.zero;
|
||||
if (!string.IsNullOrEmpty(info.pickupAudio))
|
||||
{
|
||||
item.PickupAudio = AudioTypeHandler.GetAudioType(info.pickupAudio, mod);
|
||||
@ -79,6 +83,12 @@ namespace NewHorizons.Builder.Props
|
||||
item.ClearPickupConditionOnDrop = info.clearPickupConditionOnDrop;
|
||||
item.PickupFact = info.pickupFact;
|
||||
|
||||
if (info.colliderRadius > 0f)
|
||||
{
|
||||
go.AddComponent<SphereCollider>().radius = info.colliderRadius;
|
||||
go.GetAddComponent<OWCollider>();
|
||||
}
|
||||
|
||||
Delay.FireOnNextUpdate(() =>
|
||||
{
|
||||
if (item != null && !string.IsNullOrEmpty(info.pathToInitialSocket))
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using HarmonyLib;
|
||||
using NewHorizons.External.Modules.Props;
|
||||
using NewHorizons.External.Modules.Props.EchoesOfTheEye;
|
||||
using NewHorizons.Handlers;
|
||||
@ -8,14 +9,35 @@ using OWML.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using static NewHorizons.Main;
|
||||
|
||||
namespace NewHorizons.Builder.Props
|
||||
{
|
||||
public static class ProjectionBuilder
|
||||
{
|
||||
private static GameObject _slideReelPrefab;
|
||||
public const string INVERTED_SLIDE_CACHE_FOLDER = "SlideReelCache/Inverted";
|
||||
public const string ATLAS_SLIDE_CACHE_FOLDER = "SlideReelCache/Atlas";
|
||||
|
||||
public static GameObject SlideReelWholePrefab { get; private set; }
|
||||
public static GameObject SlideReelWholePristinePrefab { get; private set; }
|
||||
public static GameObject SlideReelWholeRustedPrefab { get; private set; }
|
||||
public static GameObject SlideReelWholeDestroyedPrefab { get; private set; }
|
||||
public static GameObject SlideReel8Prefab { get; private set; }
|
||||
public static GameObject SlideReel8PristinePrefab { get; private set; }
|
||||
public static GameObject SlideReel8RustedPrefab { get; private set; }
|
||||
public static GameObject SlideReel8DestroyedPrefab { get; private set; }
|
||||
public static GameObject SlideReel7Prefab { get; private set; }
|
||||
public static GameObject SlideReel7PristinePrefab { get; private set; }
|
||||
public static GameObject SlideReel7RustedPrefab { get; private set; }
|
||||
public static GameObject SlideReel7DestroyedPrefab { get; private set; }
|
||||
public static GameObject SlideReel6Prefab { get; private set; }
|
||||
public static GameObject SlideReel6PristinePrefab { get; private set; }
|
||||
public static GameObject SlideReel6RustedPrefab { get; private set; }
|
||||
public static GameObject SlideReel6DestroyedPrefab { get; private set; }
|
||||
|
||||
private static GameObject _autoPrefab;
|
||||
private static GameObject _visionTorchDetectorPrefab;
|
||||
private static GameObject _standingVisionTorchPrefab;
|
||||
@ -23,20 +45,30 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
private static bool _isInit;
|
||||
|
||||
public static bool CacheExists(IModBehaviour mod) => Directory.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, ATLAS_SLIDE_CACHE_FOLDER));
|
||||
|
||||
internal static void InitPrefabs()
|
||||
{
|
||||
if (_isInit) return;
|
||||
|
||||
_isInit = true;
|
||||
|
||||
if (_slideReelPrefab == null)
|
||||
{
|
||||
_slideReelPrefab = SearchUtilities.Find("RingWorld_Body/Sector_RingInterior/Sector_Zone1/Sector_SlideBurningRoom_Zone1/Interactables_SlideBurningRoom_Zone1/Prefab_IP_SecretAlcove/RotationPivot/SlideReelSocket/Prefab_IP_Reel_1_LibraryPath")?.gameObject?.InstantiateInactive()?.Rename("Prefab_IP_Reel")?.DontDestroyOnLoad();
|
||||
if (_slideReelPrefab == null)
|
||||
NHLogger.LogWarning($"Tried to make slide reel prefab but couldn't. Do you have the DLC installed?");
|
||||
else
|
||||
_slideReelPrefab.AddComponent<DestroyOnDLC>()._destroyOnDLCNotOwned = true;
|
||||
}
|
||||
SlideReelWholePrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Whole");
|
||||
SlideReelWholePristinePrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_DW_Reel_Whole");
|
||||
SlideReelWholeRustedPrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Rusted_Whole");
|
||||
SlideReelWholeDestroyedPrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Destroyed_Whole");
|
||||
SlideReel8Prefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_8");
|
||||
SlideReel8PristinePrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_DW_Reel_8");
|
||||
SlideReel8RustedPrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Rusted_8");
|
||||
SlideReel8DestroyedPrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Destroyed_8");
|
||||
SlideReel7Prefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_7");
|
||||
SlideReel7PristinePrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_DW_Reel_7");
|
||||
SlideReel7RustedPrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Rusted_7");
|
||||
SlideReel7DestroyedPrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Destroyed_7");
|
||||
SlideReel6Prefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_6");
|
||||
SlideReel6PristinePrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_DW_Reel_6");
|
||||
SlideReel6RustedPrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Rusted_6");
|
||||
SlideReel6DestroyedPrefab = NHPrivateAssetBundle.LoadAsset<GameObject>("Prefab_IP_Reel_Destroyed_6");
|
||||
|
||||
if (_autoPrefab == null)
|
||||
{
|
||||
@ -88,13 +120,17 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetUniqueSlideReelID(IModBehaviour mod, SlideInfo[] slides) => $"{mod.ModHelper.Manifest.UniqueName}{slides.Join(x => x.imagePath)}".GetHashCode().ToString();
|
||||
|
||||
private static GameObject MakeSlideReel(GameObject planetGO, Sector sector, ProjectionInfo info, IModBehaviour mod)
|
||||
{
|
||||
InitPrefabs();
|
||||
|
||||
if (_slideReelPrefab == null) return null;
|
||||
GameObject prefab = GetSlideReelPrefab(info.reelModel, info.reelCondition);
|
||||
|
||||
var slideReelObj = GeneralPropBuilder.MakeFromPrefab(_slideReelPrefab, $"Prefab_IP_Reel_{mod.ModHelper.Manifest.Name}", planetGO, sector, info);
|
||||
if (prefab == null) return null;
|
||||
|
||||
var slideReelObj = GeneralPropBuilder.MakeFromPrefab(prefab, $"Prefab_IP_Reel_{GetSlideReelName(info.reelModel, info.reelCondition)}_{mod.ModHelper.Manifest.Name}", planetGO, sector, info);
|
||||
|
||||
var slideReel = slideReelObj.GetComponent<SlideReelItem>();
|
||||
slideReel.SetSector(sector);
|
||||
@ -112,41 +148,82 @@ namespace NewHorizons.Builder.Props
|
||||
var slideCollection = new SlideCollection(slidesCount);
|
||||
slideCollection.streamingAssetIdentifier = string.Empty; // NREs if null
|
||||
|
||||
// The base game ones only have 15 slides max
|
||||
var textures = new Texture2D[slidesCount >= 15 ? 15 : slidesCount];
|
||||
// We can fit 16 slides max into an atlas
|
||||
var textures = new Texture2D[slidesCount > 16 ? 16 : slidesCount];
|
||||
|
||||
var imageLoader = AddAsyncLoader(slideReelObj, mod, info.slides, ref slideCollection);
|
||||
var (invImageLoader, atlasImageLoader, imageLoader) = StartAsyncLoader(mod, info.slides, ref slideCollection, true, true);
|
||||
|
||||
// this variable just lets us track how many of the first 15 slides have been loaded.
|
||||
// this way as soon as the last one is loaded (due to async loading, this may be
|
||||
// slide 7, or slide 3, or whatever), we can build the slide reel texture. This allows us
|
||||
// to avoid doing a "is every element in the array `textures` not null" check every time a texture finishes loading
|
||||
int displaySlidesLoaded = 0;
|
||||
imageLoader.imageLoadedEvent.AddListener(
|
||||
(Texture2D tex, int index) =>
|
||||
{
|
||||
slideCollection.slides[index]._image = ImageUtilities.Invert(tex);
|
||||
// If the cache doesn't exist it will be created here, slide reels only use the base image loader for cache creation so delete the images after to free memory
|
||||
imageLoader.deleteTexturesWhenDone = !CacheExists(mod);
|
||||
|
||||
// Track the first 15 to put on the slide reel object
|
||||
if (index < textures.Length)
|
||||
var key = GetUniqueSlideReelID(mod, info.slides);
|
||||
|
||||
if (invImageLoader != null && atlasImageLoader != null)
|
||||
{
|
||||
// Loading directly from cache
|
||||
invImageLoader.imageLoadedEvent.AddListener(
|
||||
(Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
slideCollection.slides[index]._image = tex;
|
||||
}
|
||||
);
|
||||
atlasImageLoader.imageLoadedEvent.AddListener(
|
||||
(Texture2D tex, int _, string originalPath) =>
|
||||
{
|
||||
// all textures required to build the reel's textures have been loaded
|
||||
var slidesBack = slideReelObj.GetComponentInChildren<TransformAnimator>(true).transform.Find("Slides_Back").GetComponent<MeshRenderer>();
|
||||
var slidesFront = slideReelObj.GetComponentInChildren<TransformAnimator>(true).transform.Find("Slides_Front").GetComponent<MeshRenderer>();
|
||||
|
||||
// Now put together the textures into a 4x4 thing for the materials
|
||||
var reelTexture = tex;
|
||||
slidesBack.material.mainTexture = reelTexture;
|
||||
slidesBack.material.SetTexture(EmissionMap, reelTexture);
|
||||
slidesBack.material.name = reelTexture.name;
|
||||
slidesFront.material.mainTexture = reelTexture;
|
||||
slidesFront.material.SetTexture(EmissionMap, reelTexture);
|
||||
slidesFront.material.name = reelTexture.name;
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this variable just lets us track how many of the first 15 slides have been loaded.
|
||||
// this way as soon as the last one is loaded (due to async loading, this may be
|
||||
// slide 7, or slide 3, or whatever), we can build the slide reel texture. This allows us
|
||||
// to avoid doing a "is every element in the array `textures` not null" check every time a texture finishes loading
|
||||
int displaySlidesLoaded = 0;
|
||||
imageLoader.imageLoadedEvent.AddListener(
|
||||
(Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
|
||||
slideCollection.slides[index]._image = ImageUtilities.InvertSlideReel(mod, tex, originalPath);
|
||||
NHLogger.LogVerbose($"Slide reel make reel invert texture {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
// Track the first 16 to put on the slide reel object
|
||||
if (index < textures.Length)
|
||||
{
|
||||
textures[index] = tex;
|
||||
if (Interlocked.Increment(ref displaySlidesLoaded) == textures.Length)
|
||||
displaySlidesLoaded++;
|
||||
if (displaySlidesLoaded == textures.Length)
|
||||
{
|
||||
// all textures required to build the reel's textures have been loaded
|
||||
var slidesBack = slideReelObj.transform.Find("Props_IP_SlideReel_7/Slides_Back").GetComponent<MeshRenderer>();
|
||||
var slidesFront = slideReelObj.transform.Find("Props_IP_SlideReel_7/Slides_Front").GetComponent<MeshRenderer>();
|
||||
var slidesBack = slideReelObj.GetComponentInChildren<TransformAnimator>(true).transform.Find("Slides_Back").GetComponent<MeshRenderer>();
|
||||
var slidesFront = slideReelObj.GetComponentInChildren<TransformAnimator>(true).transform.Find("Slides_Front").GetComponent<MeshRenderer>();
|
||||
|
||||
// Now put together the textures into a 4x4 thing for the materials
|
||||
var reelTexture = ImageUtilities.MakeReelTexture(textures);
|
||||
var reelTexture = ImageUtilities.MakeReelTexture(mod, textures, key);
|
||||
slidesBack.material.mainTexture = reelTexture;
|
||||
slidesBack.material.SetTexture(EmissionMap, reelTexture);
|
||||
slidesBack.material.name = reelTexture.name;
|
||||
slidesFront.material.mainTexture = reelTexture;
|
||||
slidesFront.material.SetTexture(EmissionMap, reelTexture);
|
||||
slidesFront.material.name = reelTexture.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
NHLogger.LogVerbose($"Slide reel make reel texture {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
});
|
||||
}
|
||||
|
||||
// Else when you put them down you can't pick them back up
|
||||
slideReelObj.GetComponent<OWCollider>()._physicsRemoved = false;
|
||||
@ -162,6 +239,97 @@ namespace NewHorizons.Builder.Props
|
||||
return slideReelObj;
|
||||
}
|
||||
|
||||
private static GameObject GetSlideReelPrefab(ProjectionInfo.SlideReelType model, ProjectionInfo.SlideReelCondition condition)
|
||||
{
|
||||
switch (model)
|
||||
{
|
||||
case ProjectionInfo.SlideReelType.SixSlides:
|
||||
{
|
||||
switch (condition)
|
||||
{
|
||||
case ProjectionInfo.SlideReelCondition.Antique:
|
||||
default:
|
||||
return SlideReel6Prefab;
|
||||
case ProjectionInfo.SlideReelCondition.Pristine:
|
||||
return SlideReel6PristinePrefab;
|
||||
case ProjectionInfo.SlideReelCondition.Rusted:
|
||||
return SlideReel6RustedPrefab;
|
||||
}
|
||||
}
|
||||
case ProjectionInfo.SlideReelType.SevenSlides:
|
||||
default:
|
||||
{
|
||||
switch (condition)
|
||||
{
|
||||
case ProjectionInfo.SlideReelCondition.Antique:
|
||||
default:
|
||||
return SlideReel7Prefab;
|
||||
case ProjectionInfo.SlideReelCondition.Pristine:
|
||||
return SlideReel7PristinePrefab;
|
||||
case ProjectionInfo.SlideReelCondition.Rusted:
|
||||
return SlideReel7RustedPrefab;
|
||||
}
|
||||
}
|
||||
case ProjectionInfo.SlideReelType.EightSlides:
|
||||
{
|
||||
switch (condition)
|
||||
{
|
||||
case ProjectionInfo.SlideReelCondition.Antique:
|
||||
default:
|
||||
return SlideReel8Prefab;
|
||||
case ProjectionInfo.SlideReelCondition.Pristine:
|
||||
return SlideReel8PristinePrefab;
|
||||
case ProjectionInfo.SlideReelCondition.Rusted:
|
||||
return SlideReel8RustedPrefab;
|
||||
}
|
||||
}
|
||||
case ProjectionInfo.SlideReelType.Whole:
|
||||
{
|
||||
switch (condition)
|
||||
{
|
||||
case ProjectionInfo.SlideReelCondition.Antique:
|
||||
default:
|
||||
return SlideReelWholePrefab;
|
||||
case ProjectionInfo.SlideReelCondition.Pristine:
|
||||
return SlideReelWholePristinePrefab;
|
||||
case ProjectionInfo.SlideReelCondition.Rusted:
|
||||
return SlideReelWholeRustedPrefab;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetSlideReelName(ProjectionInfo.SlideReelType model, ProjectionInfo.SlideReelCondition condition)
|
||||
{
|
||||
switch (model)
|
||||
{
|
||||
case ProjectionInfo.SlideReelType.SixSlides:
|
||||
return $"6_{condition}";
|
||||
case ProjectionInfo.SlideReelType.SevenSlides:
|
||||
return $"7_{condition}";
|
||||
case ProjectionInfo.SlideReelType.EightSlides:
|
||||
return $"8_{condition}";
|
||||
case ProjectionInfo.SlideReelType.Whole:
|
||||
default:
|
||||
return $"{model}_{condition}";
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetSlideCount(ProjectionInfo.SlideReelType model)
|
||||
{
|
||||
switch (model)
|
||||
{
|
||||
case ProjectionInfo.SlideReelType.SixSlides:
|
||||
return 6;
|
||||
case ProjectionInfo.SlideReelType.SevenSlides:
|
||||
case ProjectionInfo.SlideReelType.Whole:
|
||||
return 7;
|
||||
case ProjectionInfo.SlideReelType.EightSlides:
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameObject MakeAutoProjector(GameObject planetGO, Sector sector, ProjectionInfo info, IModBehaviour mod)
|
||||
{
|
||||
InitPrefabs();
|
||||
@ -180,8 +348,29 @@ namespace NewHorizons.Builder.Props
|
||||
var slideCollection = new SlideCollection(slidesCount);
|
||||
slideCollection.streamingAssetIdentifier = string.Empty; // NREs if null
|
||||
|
||||
var imageLoader = AddAsyncLoader(projectorObj, mod, info.slides, ref slideCollection);
|
||||
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = ImageUtilities.Invert(tex); });
|
||||
var (invImageLoader, _, imageLoader) = StartAsyncLoader(mod, info.slides, ref slideCollection, true, false);
|
||||
|
||||
// Autoprojector only uses the inverted images so the original can be destroyed if they are loaded (when creating the cached inverted images)
|
||||
imageLoader.deleteTexturesWhenDone = true;
|
||||
|
||||
if (invImageLoader != null)
|
||||
{
|
||||
// Loaded directly from cache
|
||||
invImageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
slideCollection.slides[index]._image = tex;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the inverted cache from existing images
|
||||
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
slideCollection.slides[index]._image = ImageUtilities.InvertSlideReel(mod, tex, originalPath);
|
||||
NHLogger.LogVerbose($"Slide reel invert time {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
});
|
||||
}
|
||||
|
||||
slideCollectionContainer.slideCollection = slideCollection;
|
||||
|
||||
@ -219,8 +408,13 @@ namespace NewHorizons.Builder.Props
|
||||
var slideCollection = new SlideCollection(slidesCount); // TODO: uh I think that info.slides[i].playTimeDuration is not being read here... note to self for when I implement support for that: 0.7 is what to default to if playTimeDuration turns out to be 0
|
||||
slideCollection.streamingAssetIdentifier = string.Empty; // NREs if null
|
||||
|
||||
var imageLoader = AddAsyncLoader(g, mod, info.slides, ref slideCollection);
|
||||
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = tex; });
|
||||
var (_, _, imageLoader) = StartAsyncLoader(mod, info.slides, ref slideCollection, false, false);
|
||||
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
slideCollection.slides[index]._image = tex;
|
||||
NHLogger.LogVerbose($"Slide reel set time {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
});
|
||||
|
||||
// attach a component to store all the data for the slides that play when a vision torch scans this target
|
||||
var target = g.AddComponent<VisionTorchTarget>();
|
||||
@ -254,20 +448,20 @@ namespace NewHorizons.Builder.Props
|
||||
// Set some required properties on the torch
|
||||
var mindSlideProjector = standingTorch.GetComponent<MindSlideProjector>();
|
||||
mindSlideProjector._mindProjectorImageEffect = SearchUtilities.Find("Player_Body/PlayerCamera").GetComponent<MindProjectorImageEffect>();
|
||||
|
||||
|
||||
// Setup for visually supporting async texture loading
|
||||
mindSlideProjector.enabled = false;
|
||||
mindSlideProjector.enabled = false;
|
||||
var visionBeamEffect = standingTorch.FindChild("VisionBeam");
|
||||
visionBeamEffect.SetActive(false);
|
||||
|
||||
// Set up slides
|
||||
// The number of slides is unlimited, 15 is only for texturing the actual slide reel item. This is not a slide reel item
|
||||
// The number of slides is unlimited, 16 is only for texturing the actual slide reel item. This is not a slide reel item
|
||||
var slides = info.slides;
|
||||
var slidesCount = slides.Length;
|
||||
var slideCollection = new SlideCollection(slidesCount);
|
||||
slideCollection.streamingAssetIdentifier = string.Empty; // NREs if null
|
||||
|
||||
var imageLoader = AddAsyncLoader(standingTorch, mod, slides, ref slideCollection);
|
||||
var (_, _, imageLoader) = StartAsyncLoader(mod, slides, ref slideCollection, false, false);
|
||||
|
||||
// This variable just lets us track how many of the slides have been loaded.
|
||||
// This way as soon as the last one is loaded (due to async loading, this may be
|
||||
@ -275,15 +469,18 @@ namespace NewHorizons.Builder.Props
|
||||
// to avoid doing a "is every element in the array `slideCollection.slides` not null" check every time a texture finishes loading
|
||||
int displaySlidesLoaded = 0;
|
||||
imageLoader.imageLoadedEvent.AddListener(
|
||||
(Texture2D tex, int index) =>
|
||||
{
|
||||
(Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
slideCollection.slides[index]._image = tex;
|
||||
|
||||
if (Interlocked.Increment(ref displaySlidesLoaded) == slides.Length)
|
||||
displaySlidesLoaded++;
|
||||
if (displaySlidesLoaded == slides.Length)
|
||||
{
|
||||
mindSlideProjector.enabled = true;
|
||||
visionBeamEffect.SetActive(true);
|
||||
}
|
||||
NHLogger.LogVerbose($"Slide reel another set time {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
}
|
||||
);
|
||||
|
||||
@ -307,21 +504,56 @@ namespace NewHorizons.Builder.Props
|
||||
return standingTorch;
|
||||
}
|
||||
|
||||
private static ImageUtilities.AsyncImageLoader AddAsyncLoader(GameObject gameObject, IModBehaviour mod, SlideInfo[] slides, ref SlideCollection slideCollection)
|
||||
private static (SlideReelAsyncImageLoader inverted, SlideReelAsyncImageLoader atlas, SlideReelAsyncImageLoader slides)
|
||||
StartAsyncLoader(IModBehaviour mod, SlideInfo[] slides, ref SlideCollection slideCollection, bool useInvertedCache, bool useAtlasCache)
|
||||
{
|
||||
var imageLoader = gameObject.AddComponent<ImageUtilities.AsyncImageLoader>();
|
||||
var invertedImageLoader = new SlideReelAsyncImageLoader();
|
||||
var atlasImageLoader = new SlideReelAsyncImageLoader();
|
||||
var imageLoader = new SlideReelAsyncImageLoader();
|
||||
|
||||
var atlasKey = GetUniqueSlideReelID(mod, slides);
|
||||
|
||||
var cacheExists = CacheExists(mod);
|
||||
|
||||
NHLogger.Log($"Does cache exist for slide reels? {cacheExists}");
|
||||
|
||||
if (useAtlasCache && cacheExists)
|
||||
{
|
||||
NHLogger.LogVerbose($"The atlas cache for slide reel containing [{slides.FirstOrDefault(x => !string.IsNullOrEmpty(x.imagePath))?.imagePath}] is {atlasKey}");
|
||||
// Load the atlas texture used to draw onto the physical slide reel object
|
||||
atlasImageLoader.PathsToLoad.Add((0, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, ATLAS_SLIDE_CACHE_FOLDER, $"{atlasKey}.png")));
|
||||
}
|
||||
|
||||
for (int i = 0; i < slides.Length; i++)
|
||||
{
|
||||
var slide = new Slide();
|
||||
var slideInfo = slides[i];
|
||||
slide._streamingImageID = i; // for SlideRotationModule
|
||||
|
||||
if (string.IsNullOrEmpty(slideInfo.imagePath))
|
||||
{
|
||||
imageLoader.imageLoadedEvent?.Invoke(Texture2D.blackTexture, i);
|
||||
if (useInvertedCache && cacheExists)
|
||||
{
|
||||
// Load the inverted images used when displaying slide reels to a screen
|
||||
invertedImageLoader.PathsToLoad.Add((i, Path.Combine(Instance.ModHelper.Manifest.ModFolderPath, "Assets/textures/inverted_blank_slide_reel.png")));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Used to then make cached stuff
|
||||
imageLoader.PathsToLoad.Add((i, Path.Combine(Instance.ModHelper.Manifest.ModFolderPath, "Assets/textures/blank_slide_reel.png")));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
imageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, slideInfo.imagePath)));
|
||||
if (useInvertedCache && cacheExists)
|
||||
{
|
||||
// Load the inverted images used when displaying slide reels to a screen
|
||||
invertedImageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, INVERTED_SLIDE_CACHE_FOLDER, slideInfo.imagePath)));
|
||||
}
|
||||
else
|
||||
{
|
||||
imageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, slideInfo.imagePath)));
|
||||
}
|
||||
}
|
||||
|
||||
AddModules(slideInfo, ref slide, mod);
|
||||
@ -329,7 +561,36 @@ namespace NewHorizons.Builder.Props
|
||||
slideCollection.slides[i] = slide;
|
||||
}
|
||||
|
||||
return imageLoader;
|
||||
if (cacheExists)
|
||||
{
|
||||
NHLogger.Log("Loading slide reels from cache");
|
||||
|
||||
if (useAtlasCache)
|
||||
{
|
||||
atlasImageLoader.Start(false, false);
|
||||
}
|
||||
// When using the inverted cache we never need the regular images
|
||||
if (useInvertedCache)
|
||||
{
|
||||
invertedImageLoader.Start(true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
imageLoader.Start(true, false);
|
||||
}
|
||||
|
||||
return (invertedImageLoader, atlasImageLoader, imageLoader);
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.Log("Generating slide reel cache");
|
||||
|
||||
// Will be slow and create the cache if needed
|
||||
// Will run sequentially to ensure we don't run out of memory
|
||||
imageLoader.Start(true, true);
|
||||
|
||||
return (null, null, imageLoader);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddModules(SlideInfo slideInfo, ref Slide slide, IModBehaviour mod)
|
||||
@ -388,10 +649,14 @@ namespace NewHorizons.Builder.Props
|
||||
};
|
||||
modules.Add(shipLogEntry);
|
||||
}
|
||||
if (slideInfo.rotate)
|
||||
{
|
||||
modules.Add(new SlideRotationModule());
|
||||
}
|
||||
|
||||
Slide.WriteModules(modules, ref slide._modulesList, ref slide._modulesData, ref slide.lengths);
|
||||
}
|
||||
|
||||
|
||||
private static void LinkShipLogFacts(ProjectionInfo info, SlideCollectionContainer slideCollectionContainer)
|
||||
{
|
||||
// Idk why but it wants reveals to be comma delimited not a list
|
||||
|
||||
@ -4,49 +4,141 @@ using NewHorizons.Builder.Props.TranslatorText;
|
||||
using NewHorizons.Builder.ShipLog;
|
||||
using NewHorizons.External;
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Builder.Props
|
||||
{
|
||||
public static class PropBuildManager
|
||||
{
|
||||
public static string InfoToName<T>() where T : BasePropInfo
|
||||
{
|
||||
var info = typeof(T).Name;
|
||||
if (info.EndsWith("Info"))
|
||||
{
|
||||
return info.Substring(0, info.Length - 4).ToLowercaseNamingConvention();
|
||||
}
|
||||
else if (info.EndsWith("Module"))
|
||||
{
|
||||
return info.Substring(0, info.Length - 6).ToLowercaseNamingConvention();
|
||||
}
|
||||
return info.ToLowercaseNamingConvention();
|
||||
}
|
||||
|
||||
public static List<Action> nextPass;
|
||||
|
||||
public static void MakeGeneralProp<T>(GameObject go, T prop, Action<T> builder, Func<T, string> errorMessage = null) where T : BasePropInfo
|
||||
{
|
||||
if (prop != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DoesParentExist(go, prop))
|
||||
{
|
||||
builder(prop);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextPass.Add(() => MakeGeneralProp<T>(go, prop, builder, errorMessage));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var rename = !string.IsNullOrEmpty(prop.rename) ? $" [{prop.rename}]" : string.Empty;
|
||||
var extra = errorMessage != null ? $" [{errorMessage(prop)}]" : string.Empty;
|
||||
NHLogger.LogError($"Couldn't make {InfoToName<T>()}{rename}{extra} for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void MakeGeneralProps<T>(GameObject go, IEnumerable<T> props, Action<T> builder, Func<T, string> errorMessage = null) where T : BasePropInfo
|
||||
{
|
||||
if (props != null)
|
||||
{
|
||||
foreach (var prop in props)
|
||||
{
|
||||
MakeGeneralProp(go, prop, builder, errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RunMultiPass()
|
||||
{
|
||||
// Try at least 10 times going through all builders to allow for parents to be built out of order
|
||||
int i = 0;
|
||||
while (nextPass.Any())
|
||||
{
|
||||
var count = nextPass.Count;
|
||||
var passClone = nextPass.ToList();
|
||||
nextPass.Clear();
|
||||
passClone.ForEach((x) => x.Invoke());
|
||||
|
||||
if (nextPass.Count >= count || i++ > 10)
|
||||
{
|
||||
NHLogger.LogError("Couldn't find any parents. Did you write an invalid parent path?");
|
||||
|
||||
// Ignore the parent this time so that other error handling stuff can deal with these invalid paths like it used to (backwards compat)
|
||||
_ignoreParent = true;
|
||||
nextPass.ForEach((x) => x.Invoke());
|
||||
_ignoreParent = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Make(GameObject go, Sector sector, OWRigidbody planetBody, NewHorizonsBody nhBody)
|
||||
{
|
||||
PlanetConfig config = nhBody.Config;
|
||||
IModBehaviour mod = nhBody.Mod;
|
||||
|
||||
if (config.Props.gravityCannons != null)
|
||||
// If a prop has set its parentPath and the parent cannot be found, add it to the next pass and try again later
|
||||
nextPass = new List<Action>();
|
||||
|
||||
MakeGeneralProps(go, config.Props.gravityCannons, (cannon) => GravityCannonBuilder.Make(go, sector, cannon, mod), (cannon) => cannon.shuttleID);
|
||||
MakeGeneralProps(go, config.Props.shuttles, (shuttle) => ShuttleBuilder.Make(go, sector, mod, shuttle), (shuttle) => shuttle.id);
|
||||
MakeGeneralProps(go, config.Props.details, (detail) => DetailBuilder.Make(go, sector, mod, detail), (detail) => detail.path);
|
||||
MakeGeneralProps(go, config.Props.geysers, (geyser) => GeyserBuilder.Make(go, sector, geyser));
|
||||
if (Main.HasDLC) MakeGeneralProps(go, config.Props.rafts, (raft) => RaftBuilder.Make(go, sector, raft, planetBody));
|
||||
MakeGeneralProps(go, config.Props.tornados, (tornado) => TornadoBuilder.Make(go, sector, tornado, config.Atmosphere?.clouds != null));
|
||||
MakeGeneralProps(go, config.Props.volcanoes, (volcano) => VolcanoBuilder.Make(go, sector, volcano));
|
||||
MakeGeneralProps(go, config.Props.dialogue, (dialogueInfo) =>
|
||||
{
|
||||
foreach (var gravityCannonInfo in config.Props.gravityCannons)
|
||||
var (dialogue, trigger) = DialogueBuilder.Make(go, sector, dialogueInfo, mod);
|
||||
if (dialogue == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
GravityCannonBuilder.Make(go, sector, gravityCannonInfo, mod);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make gravity cannon [{gravityCannonInfo.shuttleID}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
NHLogger.LogVerbose($"[DIALOGUE] Failed to create dialogue [{dialogueInfo.xmlFile}]");
|
||||
}
|
||||
}
|
||||
if (config.Props.shuttles != null)
|
||||
{
|
||||
foreach (var shuttleInfo in config.Props.shuttles)
|
||||
{
|
||||
try
|
||||
{
|
||||
ShuttleBuilder.Make(go, sector, nhBody.Mod, shuttleInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make shuttle [{shuttleInfo.id}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, (dialogueInfo) => dialogueInfo.xmlFile);
|
||||
MakeGeneralProps(go, config.Props.entryLocation, (entryLocationInfo) => EntryLocationBuilder.Make(go, sector, entryLocationInfo, mod), (entryLocationInfo) => entryLocationInfo.id);
|
||||
// Backwards compatibility
|
||||
#pragma warning disable 612, 618
|
||||
MakeGeneralProps(go, config.Props.nomaiText, (nomaiTextInfo) => NomaiTextBuilder.Make(go, sector, nomaiTextInfo, mod), (nomaiTextInfo) => nomaiTextInfo.xmlFile);
|
||||
#pragma warning restore 612, 618
|
||||
MakeGeneralProps(go, config.Props.translatorText, (nomaiTextInfo) => TranslatorTextBuilder.Make(go, sector, nomaiTextInfo, nhBody), (nomaiTextInfo) => nomaiTextInfo.xmlFile);
|
||||
if (Main.HasDLC) MakeGeneralProps(go, config.Props.slideShows, (slideReelInfo) => ProjectionBuilder.Make(go, sector, slideReelInfo, mod), (slideReelInfo) => slideReelInfo.type.ToString().ToCamelCase());
|
||||
MakeGeneralProps(go, config.Props.singularities, (singularity) => SingularityBuilder.Make(go, sector, go.GetComponent<OWRigidbody>(), config, singularity), (singularity) => (string.IsNullOrEmpty(singularity.uniqueID) ? config.name : singularity.uniqueID));
|
||||
MakeGeneralProps(go, config.Props.signals, (signal) => SignalBuilder.Make(go, sector, signal, mod), (signal) => signal.name);
|
||||
MakeGeneralProps(go, config.Props.warpReceivers, (warpReceiver) => WarpPadBuilder.Make(go, sector, mod, warpReceiver), (warpReceiver) => warpReceiver.frequency);
|
||||
MakeGeneralProps(go, config.Props.warpTransmitters, (warpTransmitter) => WarpPadBuilder.Make(go, sector, mod, warpTransmitter), (warpTransmitter) => warpTransmitter.frequency);
|
||||
MakeGeneralProps(go, config.Props.audioSources, (audioSource) => AudioSourceBuilder.Make(go, sector, audioSource, mod), (audioSource) => audioSource.audio);
|
||||
RemoteBuilder.MakeGeneralProps(go, sector, config.Props.remotes, nhBody);
|
||||
|
||||
RunMultiPass();
|
||||
|
||||
/*
|
||||
*
|
||||
* Builders below don't inherit the same base class so if they have complicated parentPaths they might just break
|
||||
* If a prop above sets one of these as its parent path it will break (but that was always the case)
|
||||
*
|
||||
*/
|
||||
|
||||
if (config.Props.scatter != null)
|
||||
{
|
||||
try
|
||||
@ -58,156 +150,7 @@ namespace NewHorizons.Builder.Props
|
||||
NHLogger.LogError($"Couldn't make planet scatter for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
if (config.Props.details != null)
|
||||
{
|
||||
foreach (var detail in config.Props.details)
|
||||
{
|
||||
try
|
||||
{
|
||||
var detailGO = DetailBuilder.Make(go, sector, mod, detail);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make planet detail [{detail.path}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.geysers != null)
|
||||
{
|
||||
foreach (var geyserInfo in config.Props.geysers)
|
||||
{
|
||||
try
|
||||
{
|
||||
GeyserBuilder.Make(go, sector, geyserInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make geyser for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Main.HasDLC && config.Props.rafts != null)
|
||||
{
|
||||
foreach (var raftInfo in config.Props.rafts)
|
||||
{
|
||||
try
|
||||
{
|
||||
RaftBuilder.Make(go, sector, raftInfo, planetBody);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make raft for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.tornados != null)
|
||||
{
|
||||
foreach (var tornadoInfo in config.Props.tornados)
|
||||
{
|
||||
try
|
||||
{
|
||||
TornadoBuilder.Make(go, sector, tornadoInfo, config.Atmosphere?.clouds != null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make tornado for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.volcanoes != null)
|
||||
{
|
||||
foreach (var volcanoInfo in config.Props.volcanoes)
|
||||
{
|
||||
try
|
||||
{
|
||||
VolcanoBuilder.Make(go, sector, volcanoInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make volcano for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reminder that dialogue has to be built after props if they're going to be using CharacterAnimController stuff
|
||||
if (config.Props.dialogue != null)
|
||||
{
|
||||
foreach (var dialogueInfo in config.Props.dialogue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (dialogue, trigger) = DialogueBuilder.Make(go, sector, dialogueInfo, mod);
|
||||
if (dialogue == null)
|
||||
{
|
||||
NHLogger.LogVerbose($"[DIALOGUE] Failed to create dialogue [{dialogueInfo.xmlFile}]");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"[DIALOGUE] Couldn't make dialogue [{dialogueInfo.xmlFile}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.entryLocation != null)
|
||||
{
|
||||
foreach (var entryLocationInfo in config.Props.entryLocation)
|
||||
{
|
||||
try
|
||||
{
|
||||
EntryLocationBuilder.Make(go, sector, entryLocationInfo, mod);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make entry location [{entryLocationInfo.id}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Backwards compatibility
|
||||
#pragma warning disable 612, 618
|
||||
if (config.Props.nomaiText != null)
|
||||
{
|
||||
foreach (var nomaiTextInfo in config.Props.nomaiText)
|
||||
{
|
||||
try
|
||||
{
|
||||
NomaiTextBuilder.Make(go, sector, nomaiTextInfo, nhBody.Mod);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make text [{nomaiTextInfo.xmlFile}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#pragma warning restore 612, 618
|
||||
if (config.Props.translatorText != null)
|
||||
{
|
||||
foreach (var nomaiTextInfo in config.Props.translatorText)
|
||||
{
|
||||
try
|
||||
{
|
||||
TranslatorTextBuilder.Make(go, sector, nomaiTextInfo, nhBody);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make text [{nomaiTextInfo.xmlFile}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (Main.HasDLC && config.Props.slideShows != null)
|
||||
{
|
||||
foreach (var slideReelInfo in config.Props.slideShows)
|
||||
{
|
||||
try
|
||||
{
|
||||
ProjectionBuilder.Make(go, sector, slideReelInfo, mod);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make slide reel for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.quantumGroups != null)
|
||||
{
|
||||
Dictionary<string, List<GameObject>> propsByGroup = new Dictionary<string, List<GameObject>>();
|
||||
@ -235,89 +178,23 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.singularities != null)
|
||||
}
|
||||
|
||||
private static bool _ignoreParent;
|
||||
|
||||
private static bool DoesParentExist(GameObject go, BasePropInfo prop)
|
||||
{
|
||||
if (_ignoreParent)
|
||||
{
|
||||
foreach (var singularity in config.Props.singularities)
|
||||
{
|
||||
try
|
||||
{
|
||||
SingularityBuilder.Make(go, sector, go.GetComponent<OWRigidbody>(), config, singularity);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make singularity \"{(string.IsNullOrEmpty(singularity.uniqueID) ? config.name : singularity.uniqueID)}\" for [{go.name}]::\n{ex}");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (config.Props.signals != null)
|
||||
else if (string.IsNullOrEmpty(prop.parentPath))
|
||||
{
|
||||
foreach (var signal in config.Props.signals)
|
||||
{
|
||||
try
|
||||
{
|
||||
SignalBuilder.Make(go, sector, signal, mod);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make signal on planet [{config.name}] - {ex}");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (config.Props.remotes != null)
|
||||
else
|
||||
{
|
||||
foreach (var remoteInfo in config.Props.remotes)
|
||||
{
|
||||
try
|
||||
{
|
||||
RemoteBuilder.Make(go, sector, remoteInfo, nhBody);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make remote [{remoteInfo.id}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.warpReceivers != null)
|
||||
{
|
||||
foreach (var warpReceiver in config.Props.warpReceivers)
|
||||
{
|
||||
try
|
||||
{
|
||||
WarpPadBuilder.Make(go, sector, nhBody.Mod, warpReceiver);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make warp receiver [{warpReceiver.frequency}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.warpTransmitters != null)
|
||||
{
|
||||
foreach (var warpTransmitter in config.Props.warpTransmitters)
|
||||
{
|
||||
try
|
||||
{
|
||||
WarpPadBuilder.Make(go, sector, nhBody.Mod, warpTransmitter);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make warp transmitter [{warpTransmitter.frequency}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.Props.audioSources != null)
|
||||
{
|
||||
foreach (var audioSource in config.Props.audioSources)
|
||||
{
|
||||
try
|
||||
{
|
||||
AudioSourceBuilder.Make(go, sector, audioSource, mod);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make audio source [{audioSource.audio}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
return go.transform.Find(prop.parentPath) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using NewHorizons.Components.Props;
|
||||
using NewHorizons.External.Modules.Props.EchoesOfTheEye;
|
||||
using NewHorizons.Handlers;
|
||||
using NewHorizons.Utility;
|
||||
@ -73,6 +74,8 @@ namespace NewHorizons.Builder.Props
|
||||
sector.OnSectorOccupantsUpdated += lightSensor.OnSectorOccupantsUpdated;
|
||||
}
|
||||
|
||||
var nhRaftController = raftObject.AddComponent<NHRaftController>();
|
||||
|
||||
var achievementObject = new GameObject("AchievementVolume");
|
||||
achievementObject.transform.SetParent(raftObject.transform, false);
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using NewHorizons.External.Modules;
|
||||
|
||||
namespace NewHorizons.Builder.Props
|
||||
{
|
||||
@ -122,10 +123,36 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
|
||||
public static void MakeGeneralProps(GameObject go, Sector sector, RemoteInfo[] remotes, NewHorizonsBody nhBody)
|
||||
{
|
||||
if (remotes != null)
|
||||
{
|
||||
foreach (var remoteInfo in remotes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mod = nhBody.Mod;
|
||||
var id = RemoteHandler.GetPlatformID(remoteInfo.id);
|
||||
|
||||
Texture2D decal = Texture2D.whiteTexture;
|
||||
if (!string.IsNullOrWhiteSpace(remoteInfo.decalPath)) decal = ImageUtilities.GetTexture(mod, remoteInfo.decalPath, false, false, false);
|
||||
else NHLogger.LogError($"Missing decal path on [{remoteInfo.id}] for [{go.name}]");
|
||||
|
||||
PropBuildManager.MakeGeneralProp(go, remoteInfo.platform, (platform) => MakePlatform(go, sector, id, decal, platform, mod), (platform) => remoteInfo.id);
|
||||
PropBuildManager.MakeGeneralProp(go, remoteInfo.whiteboard, (whiteboard) => MakeWhiteboard(go, sector, id, decal, whiteboard, nhBody), (whiteboard) => remoteInfo.id);
|
||||
PropBuildManager.MakeGeneralProps(go, remoteInfo.stones, (stone) => MakeStone(go, sector, id, decal, stone, mod), (stone) => remoteInfo.id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't make remote [{remoteInfo.id}] for [{go.name}]:\n{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use MakeGeneralProps instead")]
|
||||
public static void Make(GameObject go, Sector sector, RemoteInfo info, NewHorizonsBody nhBody)
|
||||
{
|
||||
InitPrefabs();
|
||||
|
||||
var mod = nhBody.Mod;
|
||||
var id = RemoteHandler.GetPlatformID(info.id);
|
||||
|
||||
@ -149,7 +176,7 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
try
|
||||
{
|
||||
MakeWhiteboard(go, sector, nhBody.Mod, id, decal, info.whiteboard, nhBody);
|
||||
MakeWhiteboard(go, sector, id, decal, info.whiteboard, nhBody);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -173,8 +200,10 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
|
||||
public static void MakeWhiteboard(GameObject go, Sector sector, IModBehaviour mod, NomaiRemoteCameraPlatform.ID id, Texture2D decal, RemoteWhiteboardInfo info, NewHorizonsBody nhBody)
|
||||
public static void MakeWhiteboard(GameObject go, Sector sector, NomaiRemoteCameraPlatform.ID id, Texture2D decal, RemoteWhiteboardInfo info, NewHorizonsBody nhBody)
|
||||
{
|
||||
InitPrefabs();
|
||||
var mod = nhBody.Mod;
|
||||
var whiteboard = DetailBuilder.Make(go, sector, mod, _whiteboardPrefab, new DetailInfo(info));
|
||||
whiteboard.SetActive(false);
|
||||
|
||||
@ -213,8 +242,9 @@ namespace NewHorizons.Builder.Props
|
||||
whiteboard.SetActive(true);
|
||||
}
|
||||
|
||||
public static void MakePlatform(GameObject go, Sector sector, NomaiRemoteCameraPlatform.ID id, Texture2D decal, PlatformInfo info, IModBehaviour mod)
|
||||
public static void MakePlatform(GameObject go, Sector sector, NomaiRemoteCameraPlatform.ID id, Texture2D decal, RemotePlatformInfo info, IModBehaviour mod)
|
||||
{
|
||||
InitPrefabs();
|
||||
var platform = DetailBuilder.Make(go, sector, mod, _remoteCameraPlatformPrefab, new DetailInfo(info));
|
||||
platform.SetActive(false);
|
||||
|
||||
@ -239,8 +269,9 @@ namespace NewHorizons.Builder.Props
|
||||
platform.SetActive(true);
|
||||
}
|
||||
|
||||
public static void MakeStone(GameObject go, Sector sector, NomaiRemoteCameraPlatform.ID id, Texture2D decal, StoneInfo info, IModBehaviour mod)
|
||||
public static void MakeStone(GameObject go, Sector sector, NomaiRemoteCameraPlatform.ID id, Texture2D decal, ProjectionStoneInfo info, IModBehaviour mod)
|
||||
{
|
||||
InitPrefabs();
|
||||
var shareStone = GeneralPropBuilder.MakeFromPrefab(_shareStonePrefab, "ShareStone_" + id.ToString(), go, sector, info);
|
||||
|
||||
shareStone.GetComponent<SharedStone>()._connectedPlatform = id;
|
||||
|
||||
@ -3,6 +3,7 @@ using NewHorizons.External.Modules.Props;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.Files;
|
||||
using NewHorizons.Utility.Geometry;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -120,10 +121,28 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var parent = sector?.transform ?? go.transform;
|
||||
|
||||
if (go != null && !string.IsNullOrEmpty(propInfo.parentPath))
|
||||
{
|
||||
var newParent = go.transform.Find(propInfo.parentPath);
|
||||
if (newParent != null)
|
||||
{
|
||||
parent = newParent;
|
||||
sector = newParent.GetComponentInParent<Sector>();
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogError($"Cannot find parent object at path: {go.name}/{propInfo.parentPath}");
|
||||
}
|
||||
}
|
||||
|
||||
var prop = scatterPrefab.InstantiateInactive();
|
||||
prop.transform.SetParent(sector?.transform ?? go.transform);
|
||||
prop.transform.localPosition = go.transform.TransformPoint(point * height);
|
||||
var up = go.transform.InverseTransformPoint(prop.transform.position).normalized;
|
||||
// Have to use SetParent method to work with tidally locked bodies #872
|
||||
prop.transform.SetParent(parent, false);
|
||||
prop.transform.localPosition = point * height;
|
||||
var up = (prop.transform.position - go.transform.position).normalized;
|
||||
prop.transform.rotation = Quaternion.FromToRotation(Vector3.up, up);
|
||||
|
||||
if (propInfo.offset != null) prop.transform.localPosition += prop.transform.TransformVector(propInfo.offset);
|
||||
|
||||
@ -471,12 +471,12 @@ namespace NewHorizons.Builder.Props.TranslatorText
|
||||
|
||||
if (info.arcInfo != null && info.arcInfo.Count() != dict.Values.Count())
|
||||
{
|
||||
NHLogger.LogError($"Can't make NomaiWallText, arcInfo length [{info.arcInfo.Count()}] doesn't equal text entries [{dict.Values.Count()}]");
|
||||
NHLogger.LogError($"Can't make NomaiWallText, arcInfo length [{info.arcInfo.Count()}] doesn't equal number of TextBlocks [{dict.Values.Count()}] in the xml");
|
||||
return;
|
||||
}
|
||||
|
||||
ArcCacheData[] cachedData = null;
|
||||
if (nhBody.Cache?.ContainsKey(cacheKey) ?? false)
|
||||
if (nhBody?.Cache?.ContainsKey(cacheKey) ?? false)
|
||||
cachedData = nhBody.Cache.Get<ArcCacheData[]>(cacheKey);
|
||||
|
||||
var arranger = nomaiWallText.gameObject.AddComponent<NomaiTextArcArranger>();
|
||||
|
||||
@ -28,6 +28,7 @@ namespace NewHorizons.Builder.Props
|
||||
// Trifid is a Nomai ruins genius
|
||||
_platformContainerPrefab = SearchUtilities.Find("BrittleHollow_Body/Sector_BH/Sector_SouthHemisphere/Sector_SouthPole/Sector_Observatory/Interactables_Observatory/Prefab_NOM_RemoteViewer/Structure_NOM_RemoteViewer")
|
||||
.InstantiateInactive()
|
||||
.Rename("Prefab_NOM_PlatformContainer")
|
||||
.DontDestroyOnLoad();
|
||||
_platformContainerPrefab.transform.localScale = new Vector3(0.85f, 3f, 0.85f);
|
||||
}
|
||||
@ -39,12 +40,12 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
_detailedReceiverPrefab = new GameObject("NomaiWarpReceiver");
|
||||
|
||||
var detailedReceiver = thReceiver.InstantiateInactive();
|
||||
var detailedReceiver = thReceiver.InstantiateInactive().Rename("Prefab_NOM_WarpReceiver");
|
||||
detailedReceiver.transform.parent = _detailedReceiverPrefab.transform;
|
||||
detailedReceiver.transform.localPosition = Vector3.zero;
|
||||
detailedReceiver.transform.localRotation = Quaternion.identity;
|
||||
|
||||
var lamp = thReceiverLamp.InstantiateInactive();
|
||||
var lamp = thReceiverLamp.InstantiateInactive().Rename("Structure_NOM_WarpReceiver_Lamp");
|
||||
lamp.transform.parent = _detailedReceiverPrefab.transform;
|
||||
lamp.transform.localPosition = thReceiver.transform.InverseTransformPoint(thReceiverLamp.transform.position);
|
||||
lamp.transform.localRotation = thReceiver.transform.InverseTransformRotation(thReceiverLamp.transform.rotation);
|
||||
@ -62,10 +63,11 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
_receiverPrefab = SearchUtilities.Find("SunStation_Body/Sector_SunStation/Sector_WarpModule/Interactables_WarpModule/Prefab_NOM_WarpReceiver")
|
||||
.InstantiateInactive()
|
||||
.Rename("Prefab_NOM_WarpReceiver")
|
||||
.DontDestroyOnLoad();
|
||||
Object.Destroy(_receiverPrefab.GetComponentInChildren<NomaiWarpStreaming>().gameObject);
|
||||
|
||||
var structure = _platformContainerPrefab.Instantiate();
|
||||
var structure = _platformContainerPrefab.Instantiate().Rename("Structure_NOM_PlatformContainer");
|
||||
structure.transform.parent = _receiverPrefab.transform;
|
||||
structure.transform.localPosition = new Vector3(0, 0.8945f, 0);
|
||||
structure.transform.localRotation = Quaternion.identity;
|
||||
@ -76,10 +78,11 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
_transmitterPrefab = SearchUtilities.Find("TowerTwin_Body/Sector_TowerTwin/Sector_Tower_SS/Interactables_Tower_SS/Tower_SS_VisibleFrom_TowerTwin/Prefab_NOM_WarpTransmitter")
|
||||
.InstantiateInactive()
|
||||
.Rename("Prefab_NOM_WarpTransmitter")
|
||||
.DontDestroyOnLoad();
|
||||
Object.Destroy(_transmitterPrefab.GetComponentInChildren<NomaiWarpStreaming>().gameObject);
|
||||
|
||||
var structure = _platformContainerPrefab.Instantiate();
|
||||
var structure = _platformContainerPrefab.Instantiate().Rename("Structure_NOM_PlatformContainer");
|
||||
structure.transform.parent = _transmitterPrefab.transform;
|
||||
structure.transform.localPosition = new Vector3(0, 0.8945f, 0);
|
||||
structure.transform.localRotation = Quaternion.identity;
|
||||
@ -157,6 +160,7 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
var computerLogger = computerObject.AddComponent<NomaiWarpComputerLogger>();
|
||||
computerLogger._warpReceiver = receiver;
|
||||
computerLogger.Awake(); // Redo awake because OnReceiveWarpedBody doesn't get added to otherwise
|
||||
|
||||
computerObject.SetActive(true);
|
||||
}
|
||||
|
||||
@ -7,19 +7,47 @@ using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.Files;
|
||||
using NewHorizons.Utility.OuterWilds;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.ModHelper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using static NewHorizons.External.Modules.ShipLogModule;
|
||||
|
||||
namespace NewHorizons.Builder.ShipLog
|
||||
{
|
||||
public static class MapModeBuilder
|
||||
{
|
||||
// Takes the game object because sometimes we change the AO to an NHAO and it breaks
|
||||
private static Dictionary<GameObject, ShipLogAstroObject> _astroObjectToShipLog = new();
|
||||
|
||||
#region General
|
||||
public static ShipLogAstroObject[][] ConstructMapMode(string systemName, GameObject transformParent, ShipLogAstroObject[][] currentNav, int layer)
|
||||
{
|
||||
_astroObjectToShipLog = new();
|
||||
|
||||
// Add stock planets
|
||||
foreach (var shipLogAstroObject in currentNav.SelectMany(x => x))
|
||||
{
|
||||
var astroObject = Locator.GetAstroObject(AstroObject.StringIDToAstroObjectName(shipLogAstroObject._id));
|
||||
if (astroObject == null)
|
||||
{
|
||||
// Outsider compat
|
||||
if (shipLogAstroObject._id == "POWER_STATION")
|
||||
{
|
||||
astroObject = GameObject.FindObjectsOfType<AstroObject>().FirstOrDefault(x => x._customName == "Power Station");
|
||||
if (astroObject == null) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogError($"Couldn't find stock (?) astro object [{shipLogAstroObject?._id}]");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_astroObjectToShipLog[astroObject.gameObject] = shipLogAstroObject;
|
||||
}
|
||||
|
||||
Material greyScaleMaterial = SearchUtilities.Find(ShipLogHandler.PAN_ROOT_PATH + "/TimberHearth/Sprite").GetComponent<Image>().material;
|
||||
List<NewHorizonsBody> bodies = Main.BodyDict[systemName].Where(
|
||||
b => !(b.Config.ShipLog?.mapMode?.remove ?? false) && !b.Config.isQuantumState
|
||||
@ -30,7 +58,7 @@ namespace NewHorizons.Builder.ShipLog
|
||||
{
|
||||
if (body.Config.ShipLog == null) continue;
|
||||
|
||||
if (body.Config.ShipLog?.mapMode?.manualPosition == null)
|
||||
if (body.Config.ShipLog.mapMode?.manualPosition == null)
|
||||
{
|
||||
flagAutoPositionUsed = true;
|
||||
}
|
||||
@ -45,18 +73,46 @@ namespace NewHorizons.Builder.ShipLog
|
||||
}
|
||||
}
|
||||
|
||||
if (flagManualPositionUsed)
|
||||
// If they're both false, just default to auto (this means that no planets even have ship log info)
|
||||
if (!flagManualPositionUsed && !flagAutoPositionUsed)
|
||||
{
|
||||
if (flagAutoPositionUsed && flagManualPositionUsed)
|
||||
NHLogger.LogWarning("Can't mix manual and automatic layout of ship log map mode, defaulting to manual");
|
||||
return ConstructMapModeManual(bodies, transformParent, greyScaleMaterial, currentNav, layer);
|
||||
}
|
||||
else if (flagAutoPositionUsed)
|
||||
{
|
||||
return ConstructMapModeAuto(bodies, transformParent, greyScaleMaterial, layer);
|
||||
flagAutoPositionUsed = true;
|
||||
}
|
||||
|
||||
return null;
|
||||
var isBaseSolarSystem = systemName == "SolarSystem";
|
||||
|
||||
// Default to MANUAL in Base Solar System (we can't automatically fix them so it might just break, but AUTO breaks even more!)
|
||||
var useManual = (flagManualPositionUsed && !flagAutoPositionUsed) || (flagAutoPositionUsed && flagManualPositionUsed && isBaseSolarSystem);
|
||||
|
||||
// Default to AUTO in other solar systems (since we can actually fix them)
|
||||
var useAuto = (flagAutoPositionUsed && !flagManualPositionUsed) || (flagAutoPositionUsed && flagManualPositionUsed && !isBaseSolarSystem);
|
||||
|
||||
if (flagAutoPositionUsed && flagManualPositionUsed)
|
||||
{
|
||||
if (useAuto)
|
||||
{
|
||||
NHLogger.LogWarning("Can't mix manual and automatic layout of ship log map mode, defaulting to AUTOMATIC");
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogWarning("Can't mix manual and automatic layout of ship log map mode, defaulting to MANUAL");
|
||||
}
|
||||
}
|
||||
|
||||
ShipLogAstroObject[][] newNavMatrix = null;
|
||||
|
||||
if (useAuto)
|
||||
{
|
||||
newNavMatrix = ConstructMapModeAuto(bodies, transformParent, greyScaleMaterial, layer);
|
||||
}
|
||||
else if (useManual)
|
||||
{
|
||||
newNavMatrix = ConstructMapModeManual(bodies, transformParent, greyScaleMaterial, currentNav, layer);
|
||||
}
|
||||
|
||||
ReplaceExistingMapModeIcons();
|
||||
|
||||
return newNavMatrix;
|
||||
}
|
||||
|
||||
public static string GetAstroBodyShipLogName(string id)
|
||||
@ -109,6 +165,7 @@ namespace NewHorizons.Builder.ShipLog
|
||||
|
||||
ShipLogAstroObject astroObject = gameObject.AddComponent<ShipLogAstroObject>();
|
||||
astroObject._id = ShipLogHandler.GetAstroObjectId(body);
|
||||
_astroObjectToShipLog[body.Object] = astroObject;
|
||||
|
||||
Texture2D image = null;
|
||||
Texture2D outline = null;
|
||||
@ -124,6 +181,7 @@ namespace NewHorizons.Builder.ShipLog
|
||||
|
||||
astroObject._imageObj = CreateImage(gameObject, image, body.Config.name + " Revealed", layer);
|
||||
astroObject._outlineObj = CreateImage(gameObject, outline, body.Config.name + " Outline", layer);
|
||||
|
||||
if (ShipLogHandler.BodyHasEntries(body))
|
||||
{
|
||||
Image revealedImage = astroObject._imageObj.GetComponent<Image>();
|
||||
@ -138,6 +196,12 @@ namespace NewHorizons.Builder.ShipLog
|
||||
|
||||
Rect imageRect = astroObject._imageObj.GetComponent<RectTransform>().rect;
|
||||
astroObject._unviewedObj.transform.localPosition = new Vector3(imageRect.width / 2 + unviewedIconOffset, imageRect.height / 2 + unviewedIconOffset, 0);
|
||||
|
||||
// Set all icons inactive, they will be conditionally activated when the map mode is opened for the first time
|
||||
astroObject._unviewedObj.SetActive(false);
|
||||
astroObject._imageObj.SetActive(false);
|
||||
astroObject._outlineObj.SetActive(false);
|
||||
|
||||
return astroObject;
|
||||
}
|
||||
#endregion
|
||||
@ -475,7 +539,12 @@ namespace NewHorizons.Builder.ShipLog
|
||||
|
||||
private static void MakeNode(ref MapModeObject node, GameObject parent, Material greyScaleMaterial, int layer)
|
||||
{
|
||||
const float padding = 100f;
|
||||
// Space between this node and the previous node
|
||||
// Take whatever scale will prevent overlap
|
||||
var lastSiblingScale = node.lastSibling?.mainBody?.Config?.ShipLog?.mapMode?.scale ?? 1f;
|
||||
var scale = node.mainBody?.Config?.ShipLog?.mapMode?.scale ?? 1f;
|
||||
float padding = 100f * (scale + lastSiblingScale) / 2f;
|
||||
|
||||
Vector2 position = Vector2.zero;
|
||||
if (node.lastSibling != null)
|
||||
{
|
||||
@ -568,5 +637,68 @@ namespace NewHorizons.Builder.ShipLog
|
||||
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
#region Replacement
|
||||
private static List<(NewHorizonsBody, ModBehaviour, MapModeInfo)> _mapModIconsToUpdate = new();
|
||||
public static void TryReplaceExistingMapModeIcon(NewHorizonsBody body, ModBehaviour mod, MapModeInfo info)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(info.revealedSprite) || !string.IsNullOrEmpty(info.outlineSprite))
|
||||
{
|
||||
_mapModIconsToUpdate.Add((body, mod, info));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReplaceExistingMapModeIcons()
|
||||
{
|
||||
foreach (var (body, mod, info) in _mapModIconsToUpdate)
|
||||
{
|
||||
ReplaceExistingMapModeIcon(body, mod, info);
|
||||
}
|
||||
_mapModIconsToUpdate.Clear();
|
||||
}
|
||||
|
||||
private static void ReplaceExistingMapModeIcon(NewHorizonsBody body, ModBehaviour mod, MapModeInfo info)
|
||||
{
|
||||
var astroObject = _astroObjectToShipLog[body.Object];
|
||||
var gameObject = astroObject.gameObject;
|
||||
var layer = gameObject.layer;
|
||||
|
||||
if (!string.IsNullOrEmpty(info.revealedSprite))
|
||||
{
|
||||
var revealedTexture = ImageUtilities.GetTexture(body.Mod, info.revealedSprite);
|
||||
if (revealedTexture == null)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't load replacement revealed texture {info.revealedSprite}");
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject.Destroy(astroObject._imageObj);
|
||||
if (ShipLogHandler.IsVanillaBody(body) || ShipLogHandler.BodyHasEntries(body))
|
||||
{
|
||||
Image revealedImage = astroObject._imageObj.GetComponent<Image>();
|
||||
revealedImage.material = astroObject._greyscaleMaterial;
|
||||
revealedImage.color = Color.white;
|
||||
astroObject._image = revealedImage;
|
||||
}
|
||||
astroObject._imageObj = CreateImage(gameObject, revealedTexture, body.Config.name + " Revealed", layer);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(info.outlineSprite))
|
||||
{
|
||||
var outlineTexture = ImageUtilities.GetTexture(body.Mod, info.outlineSprite);
|
||||
if (outlineTexture == null)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't load replacement outline texture {info.outlineSprite}");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject.Destroy(astroObject._outlineObj);
|
||||
astroObject._outlineObj = CreateImage(gameObject, outlineTexture, body.Config.name + " Outline", layer);
|
||||
}
|
||||
}
|
||||
astroObject._invisibleWhenHidden = info.invisibleWhenHidden;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ namespace NewHorizons.Builder.StarSystem
|
||||
{
|
||||
if (!tex)
|
||||
{
|
||||
NHLogger.LogError($"Failed to load texture for skybox {name.ToLower()} face");
|
||||
NHLogger.LogError($"Failed to load texture for skybox {name.ToLowerInvariant()} face");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
32
NewHorizons/Components/EOTE/DreamWorldEndTimes.cs
Normal file
32
NewHorizons/Components/EOTE/DreamWorldEndTimes.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using NewHorizons.Utility.Files;
|
||||
using OWML.Common;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components.EOTE
|
||||
{
|
||||
public class DreamWorldEndTimes : MonoBehaviour
|
||||
{
|
||||
private AudioType _endTimesAudio = AudioType.EndOfTime;
|
||||
private AudioType _endTimesDreamAudio = AudioType.EndOfTime_Dream;
|
||||
|
||||
public void SetEndTimesAudio(AudioType audio)
|
||||
{
|
||||
_endTimesAudio = audio;
|
||||
}
|
||||
|
||||
public void AssignEndTimes(OWAudioSource endTimesSource) => Assign(endTimesSource, _endTimesAudio);
|
||||
|
||||
public void SetEndTimesDreamAudio(AudioType audio)
|
||||
{
|
||||
_endTimesDreamAudio = audio;
|
||||
}
|
||||
|
||||
public void AssignEndTimesDream(OWAudioSource endTimesSource) => Assign(endTimesSource, _endTimesDreamAudio);
|
||||
|
||||
public static void Assign(OWAudioSource endTimesSource, AudioType audio)
|
||||
{
|
||||
endTimesSource.Stop();
|
||||
endTimesSource.AssignAudioLibraryClip(audio);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,15 @@
|
||||
using NewHorizons.Components.Orbital;
|
||||
|
||||
namespace NewHorizons.Components.EyeOfTheUniverse
|
||||
{
|
||||
public class EyeAstroObject : AstroObject
|
||||
public class EyeAstroObject : NHAstroObject
|
||||
{
|
||||
public EyeAstroObject()
|
||||
{
|
||||
isVanilla = true;
|
||||
modUniqueName = Main.Instance.ModHelper.Manifest.UniqueName;
|
||||
}
|
||||
|
||||
public new void Awake()
|
||||
{
|
||||
_owRigidbody = GetComponent<OWRigidbody>();
|
||||
|
||||
29
NewHorizons/Components/FixPhysics.cs
Normal file
29
NewHorizons/Components/FixPhysics.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using NewHorizons.Utility.OuterWilds;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class FixPhysics : MonoBehaviour
|
||||
{
|
||||
private OWRigidbody _body;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_body = GetComponent<OWRigidbody>();
|
||||
_body._lastPosition = transform.position;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
var parentBody = _body.GetOrigParentBody();
|
||||
if (parentBody == null) return;
|
||||
_body.SetVelocity(parentBody.GetPointVelocity(_body.GetWorldCenterOfMass()));
|
||||
_body.SetAngularVelocity(parentBody.GetAngularVelocity());
|
||||
if (_body._simulateInSector) _body.OnSectorOccupantsUpdated();
|
||||
var gravity = parentBody.GetComponentInChildren<GravityVolume>();
|
||||
if (gravity != null) gravity.GetComponent<OWTriggerVolume>().AddObjectToVolume(_body.GetComponentInChildren<ForceDetector>().gameObject);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
using NewHorizons.Utility.OWML;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components.Fixers;
|
||||
|
||||
/// <summary>
|
||||
/// Fixes a bug where spawning into the ship would not trigger the hatch entryway, so the player could drown if the ship flew into water
|
||||
/// </summary>
|
||||
internal class PlayerShipAtmosphereDetectorFix : MonoBehaviour
|
||||
{
|
||||
private PlayerCameraFluidDetector _fluidDetector;
|
||||
private SimpleFluidVolume _shipAtmosphereVolume;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_fluidDetector = Locator.GetPlayerCameraDetector().GetComponent<PlayerCameraFluidDetector>();
|
||||
_shipAtmosphereVolume = Locator.GetShipBody()?.transform?.Find("Volumes/ShipAtmosphereVolume")?.GetComponent<SimpleFluidVolume>();
|
||||
if (_shipAtmosphereVolume == null)
|
||||
{
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (PlayerState.IsInsideShip())
|
||||
{
|
||||
if (!_fluidDetector._activeVolumes.Contains(_shipAtmosphereVolume))
|
||||
{
|
||||
NHLogger.LogVerbose($"{nameof(PlayerShipAtmosphereDetectorFix)} had to add the ship atmosphere volume [{_shipAtmosphereVolume}] to the fluid detector");
|
||||
_fluidDetector.AddVolume(_shipAtmosphereVolume);
|
||||
}
|
||||
NHLogger.LogVerbose($"{nameof(PlayerShipAtmosphereDetectorFix)} applied its fix");
|
||||
Component.Destroy(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,6 +30,13 @@ namespace NewHorizons.Components
|
||||
nnc._inactiveMaterial = materials[0];
|
||||
nnc._activeMaterial = materials[1];
|
||||
}
|
||||
|
||||
NomaiLamp nl = GetComponentInParent<NomaiLamp>();
|
||||
if (nl != null)
|
||||
{
|
||||
nl.enabled = true;
|
||||
nl.Awake();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
27
NewHorizons/Components/NHMapMarker.cs
Normal file
27
NewHorizons/Components/NHMapMarker.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NewHorizons.Components
|
||||
{
|
||||
public class NHMapMarker : MapMarker
|
||||
{
|
||||
public float minDisplayDistanceOverride = -1;
|
||||
public float maxDisplayDistanceOverride = -1;
|
||||
|
||||
public new void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
if (minDisplayDistanceOverride >= 0)
|
||||
{
|
||||
_minDisplayDistance = minDisplayDistanceOverride;
|
||||
}
|
||||
if (maxDisplayDistanceOverride >= 0)
|
||||
{
|
||||
_maxDisplayDistance = maxDisplayDistanceOverride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,11 @@ namespace NewHorizons.Components.Orbital
|
||||
public bool invulnerableToSun;
|
||||
public bool isVanilla;
|
||||
|
||||
/// <summary>
|
||||
/// The unique name of the mod that created this body or, if it is an existing body being edited, the last mod to edit it
|
||||
/// </summary>
|
||||
public string modUniqueName;
|
||||
|
||||
public void SetOrbitalParametersFromConfig(OrbitModule orbit)
|
||||
{
|
||||
SetOrbitalParametersFromTrueAnomaly(orbit.eccentricity, orbit.semiMajorAxis, orbit.inclination, orbit.argumentOfPeriapsis, orbit.longitudeOfAscendingNode, orbit.trueAnomaly);
|
||||
|
||||
@ -6,6 +6,8 @@ namespace NewHorizons.Components.Props
|
||||
{
|
||||
public class ConditionalObjectActivation : MonoBehaviour
|
||||
{
|
||||
private bool _playerAwake, _playerDoneAwake;
|
||||
|
||||
public GameObject GameObject;
|
||||
public string DialogueCondition;
|
||||
public bool CloseEyes;
|
||||
@ -19,6 +21,7 @@ namespace NewHorizons.Components.Props
|
||||
{
|
||||
var conditionalObjectActivationGO = new GameObject($"{go.name}_{condition}");
|
||||
var component = conditionalObjectActivationGO.AddComponent<ConditionalObjectActivation>();
|
||||
component.transform.parent = go.transform.parent;
|
||||
component.GameObject = go;
|
||||
component.DialogueCondition = condition;
|
||||
component.CloseEyes = closeEyes;
|
||||
@ -46,6 +49,7 @@ namespace NewHorizons.Components.Props
|
||||
GlobalMessenger<string, bool>.AddListener("DialogueConditionChanged", OnDialogueConditionChanged);
|
||||
GlobalMessenger.AddListener("ExitConversation", OnExitConversation);
|
||||
GlobalMessenger.AddListener("EnterConversation", OnEnterConversation);
|
||||
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
@ -53,6 +57,23 @@ namespace NewHorizons.Components.Props
|
||||
GlobalMessenger<string, bool>.RemoveListener("DialogueConditionChanged", OnDialogueConditionChanged);
|
||||
GlobalMessenger.RemoveListener("ExitConversation", OnExitConversation);
|
||||
GlobalMessenger.RemoveListener("EnterConversation", OnEnterConversation);
|
||||
GlobalMessenger.RemoveListener("WakeUp", OnWakeUp);
|
||||
}
|
||||
|
||||
private void OnWakeUp()
|
||||
{
|
||||
_playerAwake = true;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (!_playerDoneAwake && _playerAwake)
|
||||
{
|
||||
if (!_playerCameraEffectController._isOpeningEyes)
|
||||
{
|
||||
_playerDoneAwake = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnExitConversation()
|
||||
@ -87,7 +108,7 @@ namespace NewHorizons.Components.Props
|
||||
|
||||
public void SetActive(bool active)
|
||||
{
|
||||
if (CloseEyes)
|
||||
if (CloseEyes && _playerDoneAwake && LateInitializerManager.isDoneInitializing)
|
||||
{
|
||||
Delay.StartCoroutine(Coroutine(active));
|
||||
}
|
||||
|
||||
@ -19,6 +19,10 @@ namespace NewHorizons.Components.Props
|
||||
public AudioType DropAudio;
|
||||
public AudioType SocketAudio;
|
||||
public AudioType UnsocketAudio;
|
||||
public Vector3 HoldOffset;
|
||||
public Vector3 HoldRotation;
|
||||
public Vector3 SocketOffset;
|
||||
public Vector3 SocketRotation;
|
||||
public string PickupCondition;
|
||||
public bool ClearPickupConditionOnDrop;
|
||||
public string PickupFact;
|
||||
@ -42,6 +46,8 @@ namespace NewHorizons.Components.Props
|
||||
public override void PickUpItem(Transform holdTranform)
|
||||
{
|
||||
base.PickUpItem(holdTranform);
|
||||
transform.localPosition = HoldOffset;
|
||||
transform.localEulerAngles = HoldRotation;
|
||||
TriggerPickupConditions();
|
||||
PlayCustomSound(PickupAudio);
|
||||
}
|
||||
@ -56,6 +62,8 @@ namespace NewHorizons.Components.Props
|
||||
public override void SocketItem(Transform socketTransform, Sector sector)
|
||||
{
|
||||
base.SocketItem(socketTransform, sector);
|
||||
transform.localPosition = SocketOffset;
|
||||
transform.localEulerAngles = SocketRotation;
|
||||
TriggerDropConditions();
|
||||
PlayCustomSound(SocketAudio);
|
||||
}
|
||||
|
||||
33
NewHorizons/Components/Props/NHRaftController.cs
Normal file
33
NewHorizons/Components/Props/NHRaftController.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components.Props
|
||||
{
|
||||
public class NHRaftController : MonoBehaviour
|
||||
{
|
||||
RaftController raft;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
raft = GetComponent<RaftController>();
|
||||
raft._fluidDetector.OnEnterFluid += OnEnterFluid;
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
{
|
||||
raft._fluidDetector.OnEnterFluid -= OnEnterFluid;
|
||||
}
|
||||
|
||||
private void OnEnterFluid(FluidVolume volume)
|
||||
{
|
||||
if (volume.GetFluidType() == FluidVolume.Type.WATER)
|
||||
{
|
||||
raft._fluidDetector._alignmentFluid = volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,7 +188,11 @@ namespace NewHorizons.Components.Props
|
||||
{
|
||||
for (int i = 0; i < _ambientLight.Length; i++)
|
||||
{
|
||||
_ambientLight[i].intensity = _ambientLightOrigIntensity[i] * (1f - collapseProgress);
|
||||
var ambientLight = _ambientLight[i];
|
||||
if (ambientLight != null)
|
||||
{
|
||||
ambientLight.intensity = _ambientLightOrigIntensity[i] * (1f - collapseProgress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,16 @@ namespace NewHorizons.Components.Quantum
|
||||
private OWRigidbody _rb;
|
||||
private OrbitLine _orbitLine;
|
||||
|
||||
public NHAstroObject astroObject
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_astroObject == null)
|
||||
_astroObject = GetComponent<NHAstroObject>();
|
||||
return _astroObject;
|
||||
}
|
||||
}
|
||||
|
||||
public int CurrentIndex { get; private set; }
|
||||
|
||||
public override void Awake()
|
||||
@ -97,7 +107,7 @@ namespace NewHorizons.Components.Quantum
|
||||
|
||||
primaryBody = AstroObjectLocator.GetAstroObject(newOrbit.primaryBody);
|
||||
var primaryGravity = new Gravity(primaryBody.GetGravityVolume());
|
||||
var secondaryGravity = new Gravity(_astroObject.GetGravityVolume());
|
||||
var secondaryGravity = new Gravity(astroObject.GetGravityVolume());
|
||||
orbitalParams = newOrbit.GetOrbitalParameters(primaryGravity, secondaryGravity);
|
||||
|
||||
var pos = primaryBody.transform.position + orbitalParams.InitialPosition;
|
||||
@ -139,15 +149,16 @@ namespace NewHorizons.Components.Quantum
|
||||
|
||||
private void SetNewOrbit(AstroObject primaryBody, OrbitalParameters orbitalParameters)
|
||||
{
|
||||
_astroObject._primaryBody = primaryBody;
|
||||
DetectorBuilder.SetDetector(primaryBody, _astroObject, _detector);
|
||||
astroObject._primaryBody = primaryBody;
|
||||
DetectorBuilder.SetDetector(primaryBody, astroObject, _detector);
|
||||
_detector._activeInheritedDetector = primaryBody.GetComponentInChildren<ForceDetector>();
|
||||
_detector._activeVolumes = new List<EffectVolume>() { primaryBody.GetGravityVolume() };
|
||||
if (_alignment != null) _alignment.SetTargetBody(primaryBody.GetComponent<OWRigidbody>());
|
||||
|
||||
_astroObject.SetOrbitalParametersFromTrueAnomaly(orbitalParameters.eccentricity, orbitalParameters.semiMajorAxis, orbitalParameters.inclination, orbitalParameters.argumentOfPeriapsis, orbitalParameters.longitudeOfAscendingNode, orbitalParameters.trueAnomaly);
|
||||
astroObject.SetOrbitalParametersFromTrueAnomaly(orbitalParameters.eccentricity, orbitalParameters.semiMajorAxis, orbitalParameters.inclination, orbitalParameters.argumentOfPeriapsis, orbitalParameters.longitudeOfAscendingNode, orbitalParameters.trueAnomaly);
|
||||
|
||||
PlanetCreationHandler.UpdatePosition(gameObject, orbitalParameters, primaryBody, _astroObject);
|
||||
PlanetCreationHandler.UpdatePosition(gameObject, orbitalParameters, primaryBody, astroObject);
|
||||
gameObject.transform.parent = null;
|
||||
|
||||
if (!Physics.autoSyncTransforms)
|
||||
{
|
||||
|
||||
@ -33,13 +33,16 @@ namespace NewHorizons.Components.Sectored
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
DisableRenderers();
|
||||
}
|
||||
|
||||
private void GetRenderers()
|
||||
{
|
||||
_renderers = gameObject.GetComponentsInChildren<Renderer>();
|
||||
_tessellatedRenderers = gameObject.GetComponentsInChildren<TessellatedRenderer>();
|
||||
_colliders = gameObject.GetComponentsInChildren<Collider>();
|
||||
_lights = gameObject.GetComponentsInChildren<Light>();
|
||||
|
||||
DisableRenderers();
|
||||
}
|
||||
|
||||
private void OnSectorOccupantsUpdated()
|
||||
@ -54,54 +57,35 @@ namespace NewHorizons.Components.Sectored
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableRenderers()
|
||||
private void EnableRenderers() => ToggleRenderers(true);
|
||||
|
||||
private void DisableRenderers() => ToggleRenderers(false);
|
||||
|
||||
private void ToggleRenderers(bool visible)
|
||||
{
|
||||
GetRenderers();
|
||||
|
||||
foreach (var renderer in _renderers)
|
||||
{
|
||||
renderer.forceRenderingOff = false;
|
||||
renderer.forceRenderingOff = !visible;
|
||||
}
|
||||
|
||||
foreach (var tessellatedRenderer in _tessellatedRenderers)
|
||||
{
|
||||
tessellatedRenderer.enabled = true;
|
||||
tessellatedRenderer.enabled = visible;
|
||||
}
|
||||
|
||||
foreach (var collider in _colliders)
|
||||
{
|
||||
collider.enabled = true;
|
||||
collider.enabled = visible;
|
||||
}
|
||||
|
||||
foreach (var light in _lights)
|
||||
{
|
||||
light.enabled = true;
|
||||
light.enabled = visible;
|
||||
}
|
||||
|
||||
_renderersShown = true;
|
||||
}
|
||||
|
||||
private void DisableRenderers()
|
||||
{
|
||||
foreach (var renderer in _renderers)
|
||||
{
|
||||
renderer.forceRenderingOff = true;
|
||||
}
|
||||
|
||||
foreach (var tessellatedRenderer in _tessellatedRenderers)
|
||||
{
|
||||
tessellatedRenderer.enabled = false;
|
||||
}
|
||||
|
||||
foreach (var collider in _colliders)
|
||||
{
|
||||
collider.enabled = false;
|
||||
}
|
||||
|
||||
foreach (var light in _lights)
|
||||
{
|
||||
light.enabled = false;
|
||||
}
|
||||
|
||||
_renderersShown = false;
|
||||
_renderersShown = visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,12 +47,6 @@ namespace NewHorizons.Components.Ship
|
||||
public void Start()
|
||||
{
|
||||
_isWarpingIn = false;
|
||||
GlobalMessenger.AddListener("FinishOpenEyes", new Callback(OnFinishOpenEyes));
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
GlobalMessenger.RemoveListener("FinishOpenEyes", new Callback(OnFinishOpenEyes));
|
||||
}
|
||||
|
||||
private void MakeBlackHole()
|
||||
@ -144,6 +138,12 @@ namespace NewHorizons.Components.Ship
|
||||
resources._currentHealth = 100f;
|
||||
if (!PlayerState.AtFlightConsole()) TeleportToShip();
|
||||
}
|
||||
|
||||
if (PlayerState.IsInsideShip() && !_eyesOpen)
|
||||
{
|
||||
_eyesOpen = true;
|
||||
Locator.GetPlayerCamera().GetComponent<PlayerCameraEffectController>().OpenEyesImmediate();
|
||||
}
|
||||
}
|
||||
|
||||
// Idk whats making this work but now it works and idc
|
||||
@ -154,11 +154,6 @@ namespace NewHorizons.Components.Ship
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFinishOpenEyes()
|
||||
{
|
||||
_eyesOpen = true;
|
||||
}
|
||||
|
||||
private void StartWarpInEffect()
|
||||
{
|
||||
NHLogger.LogVerbose("Starting warp-in effect");
|
||||
@ -203,6 +198,7 @@ namespace NewHorizons.Components.Ship
|
||||
PlayerState.OnEnterShip();
|
||||
|
||||
PlayerSpawnHandler.SpawnShip();
|
||||
OWInput.ChangeInputMode(InputMode.ShipCockpit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,10 +34,13 @@ namespace NewHorizons.Components.ShipLog
|
||||
|
||||
private int _nextCardIndex;
|
||||
|
||||
private HashSet<string> _systemCards = new();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Prompts
|
||||
Locator.GetPromptManager().AddScreenPrompt(_warpPrompt, PromptPosition.UpperLeft, false);
|
||||
_systemCards.Clear();
|
||||
}
|
||||
|
||||
public override void Initialize(ScreenPromptList centerPromptList, ScreenPromptList upperRightPromptList, OWAudioSource oneShotSource)
|
||||
@ -70,8 +73,15 @@ namespace NewHorizons.Components.ShipLog
|
||||
|
||||
public void AddSystemCard(string uniqueID)
|
||||
{
|
||||
var card = CreateCard(uniqueID, root.transform, new Vector2(_nextCardIndex++ * 200, 0));
|
||||
_starSystemCards.Add(card);
|
||||
if (!_systemCards.Contains(uniqueID))
|
||||
{
|
||||
var card = CreateCard(uniqueID, root.transform, new Vector2(_nextCardIndex++ * 200, 0));
|
||||
_starSystemCards.Add(card);
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogWarning($"Tried making duplicate system card {uniqueID}");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
@ -86,7 +96,7 @@ namespace NewHorizons.Components.ShipLog
|
||||
if (_cardTemplate == null)
|
||||
{
|
||||
var panRoot = SearchUtilities.Find("Ship_Body/Module_Cabin/Systems_Cabin/ShipLogPivot/ShipLog/ShipLogPivot/ShipLogCanvas/DetectiveMode/ScaleRoot/PanRoot");
|
||||
_cardTemplate = Instantiate(panRoot.GetComponentInChildren<ShipLogEntryCard>().gameObject);
|
||||
_cardTemplate = Instantiate(panRoot.GetComponentInChildren<ShipLogEntryCard>(true).gameObject);
|
||||
_cardTemplate.SetActive(false);
|
||||
}
|
||||
|
||||
@ -199,6 +209,12 @@ namespace NewHorizons.Components.ShipLog
|
||||
|
||||
private void UpdateMapCamera()
|
||||
{
|
||||
if (_starSystemCards.Count == 0)
|
||||
{
|
||||
NHLogger.LogWarning("Showing star chart mode when there are no avaialble systems");
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 b = -_starSystemCards[_cardIndex].transform.localPosition;
|
||||
float num = Mathf.InverseLerp(_startPanTime, _startPanTime + _panDuration, Time.unscaledTime);
|
||||
num = 1f - (num - 1f) * (num - 1f);
|
||||
@ -282,7 +298,7 @@ namespace NewHorizons.Components.ShipLog
|
||||
|
||||
var name = UniqueIDToName(shipLogEntryCard.name);
|
||||
|
||||
var warpNotificationDataText = TranslationHandler.GetTranslation("WARP_LOCKED", TranslationHandler.TextType.UI).Replace("{0}", name.ToUpper());
|
||||
var warpNotificationDataText = TranslationHandler.GetTranslation("WARP_LOCKED", TranslationHandler.TextType.UI).Replace("{0}", name.ToUpperFixed());
|
||||
_warpNotificationData = new NotificationData(warpNotificationDataText);
|
||||
NotificationManager.SharedInstance.PostNotification(_warpNotificationData, true);
|
||||
|
||||
|
||||
@ -13,6 +13,9 @@ namespace NewHorizons.Components
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// So that mods can turn the time loop on/off using the TimLoop.SetTimeLoopEnabled method
|
||||
if (!TimeLoop._timeLoopEnabled) return;
|
||||
|
||||
// Stock gives like 33 seconds after the sun collapses
|
||||
if (_supernovaHappened && Time.time > _supernovaTime + 50f)
|
||||
{
|
||||
|
||||
@ -45,11 +45,55 @@ namespace NewHorizons.Components
|
||||
_powerOrb.AddLock();
|
||||
}
|
||||
|
||||
public void RemoveLocks()
|
||||
public void RemoveLockFromCoordinateOrb()
|
||||
{
|
||||
_coordinateInterfaceOrb.RemoveLock();
|
||||
}
|
||||
|
||||
public void RemoveLockFromWarpOrb()
|
||||
{
|
||||
_coordinateInterfaceUpperOrb.RemoveLock();
|
||||
}
|
||||
|
||||
public void RemoveLockFromPowerOrb()
|
||||
{
|
||||
_powerOrb.RemoveLock();
|
||||
}
|
||||
|
||||
public void RemoveAllLocksFromCoordinateOrb()
|
||||
{
|
||||
_coordinateInterfaceOrb.RemoveAllLocks();
|
||||
}
|
||||
|
||||
public void RemoveAllLocksFromWarpOrb()
|
||||
{
|
||||
_coordinateInterfaceUpperOrb.RemoveAllLocks();
|
||||
}
|
||||
|
||||
public void RemoveAllLocksFromPowerOrb()
|
||||
{
|
||||
_powerOrb.RemoveAllLocks();
|
||||
}
|
||||
|
||||
public void AddLock()
|
||||
{
|
||||
AddLockToCoordinateOrb();
|
||||
AddLockToWarpOrb();
|
||||
AddLockToPowerOrb();
|
||||
}
|
||||
|
||||
public void RemoveLock()
|
||||
{
|
||||
RemoveLockFromCoordinateOrb();
|
||||
RemoveLockFromWarpOrb();
|
||||
RemoveLockFromPowerOrb();
|
||||
}
|
||||
|
||||
public void RemoveAllLocks()
|
||||
{
|
||||
RemoveAllLocksFromCoordinateOrb();
|
||||
RemoveAllLocksFromWarpOrb();
|
||||
RemoveAllLocksFromPowerOrb();
|
||||
}
|
||||
}
|
||||
}
|
||||
78
NewHorizons/Components/Vessel/VesselSpawnPoint.cs
Normal file
78
NewHorizons/Components/Vessel/VesselSpawnPoint.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using NewHorizons.Handlers;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components
|
||||
{
|
||||
[UsedInUnityProject]
|
||||
public class VesselSpawnPoint : EyeSpawnPoint
|
||||
{
|
||||
public GameObject warpControllerObject;
|
||||
private VesselWarpController _warpController;
|
||||
|
||||
public VesselWarpController WarpController
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_warpController == null && warpControllerObject != null) WarpController = warpControllerObject.GetComponent<VesselWarpController>();
|
||||
return _warpController;
|
||||
}
|
||||
set
|
||||
{
|
||||
_warpController = value;
|
||||
if (_warpController != null) _triggerVolumes = new OWTriggerVolume[1] { _warpController._bridgeVolume };
|
||||
}
|
||||
}
|
||||
|
||||
public VesselSpawnPoint()
|
||||
{
|
||||
_eyeState = EyeState.AboardVessel;
|
||||
}
|
||||
|
||||
public int index = 0;
|
||||
|
||||
public void WarpPlayer(bool spawn = false)
|
||||
{
|
||||
var warpController = WarpController;
|
||||
var player = Locator.GetPlayerBody();
|
||||
var relativeTransform = warpController.transform;
|
||||
var relativeBody = relativeTransform.GetAttachedOWRigidbody();
|
||||
if (!spawn) Locator.GetPlayerCamera().GetComponent<PlayerCameraEffectController>().OpenEyesImmediate();
|
||||
if (VesselWarpController.s_relativeLocationSaved)
|
||||
{
|
||||
Locator.GetPlayerBody().MoveToRelativeLocation(VesselWarpController.s_playerWarpLocation, relativeBody, relativeTransform);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.SetPosition(warpController._defaultPlayerWarpPoint.position);
|
||||
player.SetRotation(warpController._defaultPlayerWarpPoint.rotation);
|
||||
player.SetVelocity(relativeBody.GetPointVelocity(warpController._defaultPlayerWarpPoint.position));
|
||||
}
|
||||
AddPlayerToVolume(warpController._bridgeVolume);
|
||||
AddPlayerToTriggerVolumes();
|
||||
}
|
||||
|
||||
public override void OnSpawnPlayer()
|
||||
{
|
||||
Delay.FireOnNextUpdate(() => WarpPlayer(true));
|
||||
}
|
||||
|
||||
public void AddPlayerToVolume(OWTriggerVolume volume)
|
||||
{
|
||||
volume.AddObjectToVolume(Locator.GetPlayerDetector());
|
||||
volume.AddObjectToVolume(Locator.GetPlayerCameraDetector());
|
||||
}
|
||||
|
||||
public void AddPlayerToTriggerVolumes()
|
||||
{
|
||||
AddObjectToTriggerVolumes(Locator.GetPlayerDetector());
|
||||
AddObjectToTriggerVolumes(Locator.GetPlayerCameraDetector());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,22 +3,27 @@ using UnityEngine;
|
||||
namespace NewHorizons.Components.Volumes
|
||||
{
|
||||
[RequireComponent(typeof(OWTriggerVolume))]
|
||||
public abstract class BaseVolume : MonoBehaviour
|
||||
public abstract class BaseVolume : SectoredMonoBehaviour
|
||||
{
|
||||
private OWTriggerVolume _triggerVolume;
|
||||
|
||||
public virtual void Awake()
|
||||
public override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_triggerVolume = this.GetRequiredComponent<OWTriggerVolume>();
|
||||
_triggerVolume.OnEntry += OnTriggerVolumeEntry;
|
||||
_triggerVolume.OnExit += OnTriggerVolumeExit;
|
||||
}
|
||||
|
||||
public virtual void OnDestroy()
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (_triggerVolume == null) return;
|
||||
_triggerVolume.OnEntry -= OnTriggerVolumeEntry;
|
||||
_triggerVolume.OnExit -= OnTriggerVolumeExit;
|
||||
base.OnDestroy();
|
||||
|
||||
if (_triggerVolume != null)
|
||||
{
|
||||
_triggerVolume.OnEntry -= OnTriggerVolumeEntry;
|
||||
_triggerVolume.OnExit -= OnTriggerVolumeExit;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void OnTriggerVolumeEntry(GameObject hitObj);
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
namespace NewHorizons.Components.Volumes
|
||||
{
|
||||
public class NHInnerFogWarpVolume : InnerFogWarpVolume
|
||||
{
|
||||
public override bool IsProbeOnly() => _exitRadius <= 6;
|
||||
public override float GetFogThickness() => _exitRadius;
|
||||
}
|
||||
}
|
||||
128
NewHorizons/Components/Volumes/StreamingWarpVolume.cs
Normal file
128
NewHorizons/Components/Volumes/StreamingWarpVolume.cs
Normal file
@ -0,0 +1,128 @@
|
||||
using NewHorizons.Utility.OWML;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Components.Volumes
|
||||
{
|
||||
/// <summary>
|
||||
/// Currently only relevant for Vanilla planets, which actually have streaming groups
|
||||
/// </summary>
|
||||
internal class StreamingWarpVolume : BaseVolume
|
||||
{
|
||||
public StreamingGroup streamingGroup;
|
||||
private bool _probeInVolume;
|
||||
private bool _playerInVolume;
|
||||
private bool _preloadingRequiredAssets;
|
||||
private bool _preloadingGeneralAssets;
|
||||
|
||||
private SurveyorProbe _probe;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_probe = Locator.GetProbe();
|
||||
base.enabled = false;
|
||||
}
|
||||
|
||||
public void FixedUpdate()
|
||||
{
|
||||
// Bug report on Astral Codec mod page - Huge lag inside streaming warp volume, possible NRE?
|
||||
if (_probe == null)
|
||||
{
|
||||
_probe = Locator.GetProbe();
|
||||
if (_probe == null)
|
||||
{
|
||||
NHLogger.LogError($"How is your scout probe null? Destroying {nameof(StreamingWarpVolume)}");
|
||||
GameObject.DestroyImmediate(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (streamingGroup == null)
|
||||
{
|
||||
NHLogger.LogError($"{nameof(StreamingWarpVolume)} has no streaming group. Destroying {nameof(StreamingWarpVolume)}");
|
||||
GameObject.DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
bool probeActive = _probe.IsLaunched() && !_probe.IsAnchored();
|
||||
|
||||
bool shouldBeLoadingRequiredAssets = _playerInVolume || (_probeInVolume && probeActive);
|
||||
bool shouldBeLoadingGeneralAssets = _playerInVolume;
|
||||
|
||||
UpdatePreloadingState(shouldBeLoadingRequiredAssets, shouldBeLoadingGeneralAssets);
|
||||
}
|
||||
|
||||
private void UpdatePreloadingState(bool shouldBeLoadingRequiredAssets, bool shouldBeLoadingGeneralAssets)
|
||||
{
|
||||
if (!this._preloadingRequiredAssets && shouldBeLoadingRequiredAssets)
|
||||
{
|
||||
this.streamingGroup.RequestRequiredAssets(0);
|
||||
this._preloadingRequiredAssets = true;
|
||||
}
|
||||
else if (this._preloadingRequiredAssets && !shouldBeLoadingRequiredAssets)
|
||||
{
|
||||
this.streamingGroup.ReleaseRequiredAssets();
|
||||
this._preloadingRequiredAssets = false;
|
||||
}
|
||||
if (!this._preloadingGeneralAssets && shouldBeLoadingGeneralAssets)
|
||||
{
|
||||
this.streamingGroup.RequestGeneralAssets(0);
|
||||
this._preloadingGeneralAssets = true;
|
||||
return;
|
||||
}
|
||||
if (this._preloadingGeneralAssets && !shouldBeLoadingGeneralAssets)
|
||||
{
|
||||
this.streamingGroup.ReleaseGeneralAssets();
|
||||
this._preloadingGeneralAssets = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSectorOccupantsUpdated()
|
||||
{
|
||||
if (this._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe))
|
||||
{
|
||||
if (StreamingManager.isStreamingEnabled && this.streamingGroup != null)
|
||||
{
|
||||
base.enabled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.UpdatePreloadingState(false, false);
|
||||
base.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnTriggerVolumeEntry(GameObject hitObj)
|
||||
{
|
||||
OWRigidbody attachedOWRigidbody = hitObj.GetAttachedOWRigidbody(false);
|
||||
if (attachedOWRigidbody != null)
|
||||
{
|
||||
if (attachedOWRigidbody.CompareTag("Player"))
|
||||
{
|
||||
this._playerInVolume = true;
|
||||
return;
|
||||
}
|
||||
if (attachedOWRigidbody.CompareTag("Probe"))
|
||||
{
|
||||
this._probeInVolume = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnTriggerVolumeExit(GameObject hitObj)
|
||||
{
|
||||
OWRigidbody attachedOWRigidbody = hitObj.GetAttachedOWRigidbody(false);
|
||||
if (attachedOWRigidbody != null)
|
||||
{
|
||||
if (attachedOWRigidbody.CompareTag("Player"))
|
||||
{
|
||||
this._playerInVolume = false;
|
||||
return;
|
||||
}
|
||||
if (attachedOWRigidbody.CompareTag("Probe"))
|
||||
{
|
||||
this._probeInVolume = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
NewHorizons/External/Configs/AddonConfig.cs
vendored
12
NewHorizons/External/Configs/AddonConfig.cs
vendored
@ -31,5 +31,17 @@ namespace NewHorizons.External.Configs
|
||||
/// If popupMessage is set, should it repeat every time the game starts or only once
|
||||
/// </summary>
|
||||
public bool repeatPopup;
|
||||
|
||||
/// <summary>
|
||||
/// These asset bundles will be loaded on the title screen and stay loaded. Will improve initial load time at the cost of increased memory use.
|
||||
/// The path is the relative directory of the asset bundle in the mod folder.
|
||||
/// </summary>
|
||||
public string[] preloadAssetBundles;
|
||||
|
||||
/// <summary>
|
||||
/// The path to the addons subtitle for the main menu.
|
||||
/// Defaults to "subtitle.png".
|
||||
/// </summary>
|
||||
public string subtitlePath = "subtitle.png";
|
||||
}
|
||||
}
|
||||
|
||||
9
NewHorizons/External/Configs/PlanetConfig.cs
vendored
9
NewHorizons/External/Configs/PlanetConfig.cs
vendored
@ -113,6 +113,11 @@ namespace NewHorizons.External.Configs
|
||||
/// </summary>
|
||||
public LavaModule Lava;
|
||||
|
||||
/// <summary>
|
||||
/// Map marker properties of this body
|
||||
/// </summary>
|
||||
public MapMarkerModule MapMarker;
|
||||
|
||||
/// <summary>
|
||||
/// Describes this Body's orbit (or lack there of)
|
||||
/// </summary>
|
||||
@ -213,8 +218,8 @@ namespace NewHorizons.External.Configs
|
||||
// Always have to have a base module
|
||||
if (Base == null) Base = new BaseModule();
|
||||
if (Orbit == null) Orbit = new OrbitModule();
|
||||
if (ShipLog == null) ShipLog = new ShipLogModule();
|
||||
if (ReferenceFrame == null) ReferenceFrame = new ReferenceFrameModule();
|
||||
if (MapMarker == null) MapMarker = new MapMarkerModule();
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
@ -308,6 +313,8 @@ namespace NewHorizons.External.Configs
|
||||
|
||||
if (!Base.hasReferenceFrame) ReferenceFrame.enabled = false;
|
||||
|
||||
if (Base.hasMapMarker) MapMarker.enabled = true;
|
||||
|
||||
if (childrenToDestroy != null) removeChildren = childrenToDestroy;
|
||||
|
||||
if (Base.cloakRadius != 0)
|
||||
|
||||
106
NewHorizons/External/Configs/StarSystemConfig.cs
vendored
106
NewHorizons/External/Configs/StarSystemConfig.cs
vendored
@ -2,6 +2,7 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.External.SerializableData;
|
||||
using Newtonsoft.Json;
|
||||
@ -31,10 +32,29 @@ namespace NewHorizons.External.Configs
|
||||
public float farClipPlaneOverride;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this system can be warped to via the warp drive. If you set factRequiredForWarp, this will be true.
|
||||
/// Whether this system can be warped to via the warp drive. If you set `factRequiredForWarp`, this will be true.
|
||||
/// Does NOT effect the base SolarSystem. For that, see `canExitViaWarpDrive` and `factRequiredToExitViaWarpDrive`
|
||||
/// </summary>
|
||||
[DefaultValue(true)] public bool canEnterViaWarpDrive = true;
|
||||
|
||||
/// <summary>
|
||||
/// The FactID that must be revealed before it can be warped to. Don't set `canEnterViaWarpDrive` to `false` if
|
||||
/// you're using this, because it will be overwritten.
|
||||
/// </summary>
|
||||
public string factRequiredForWarp;
|
||||
|
||||
/// <summary>
|
||||
/// Can you use the warp drive to leave this system? If you set `factRequiredToExitViaWarpDrive`
|
||||
/// this will be true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)] public bool canExitViaWarpDrive = true;
|
||||
|
||||
/// <summary>
|
||||
/// The FactID that must be revealed for you to warp back to the main solar system from here. Don't set `canWarpHome`
|
||||
/// to `false` if you're using this, because it will be overwritten.
|
||||
/// </summary>
|
||||
public string factRequiredToExitViaWarpDrive;
|
||||
|
||||
/// <summary>
|
||||
/// Do you want a clean slate for this star system? Or will it be a modified version of the original.
|
||||
/// </summary>
|
||||
@ -45,12 +65,6 @@ namespace NewHorizons.External.Configs
|
||||
/// </summary>
|
||||
[DefaultValue(true)] public bool enableTimeLoop = true;
|
||||
|
||||
/// <summary>
|
||||
/// The FactID that must be revealed before it can be warped to. Don't set `canEnterViaWarpDrive` to `false` if
|
||||
/// you're using this, because it will be overwritten.
|
||||
/// </summary>
|
||||
public string factRequiredForWarp;
|
||||
|
||||
/// <summary>
|
||||
/// The duration of the time loop in minutes. This is the time the sun explodes. End Times plays 85 seconds before this time, and your memories get sent back about 40 seconds after this time.
|
||||
/// </summary>
|
||||
@ -82,11 +96,14 @@ namespace NewHorizons.External.Configs
|
||||
[Obsolete("travelAudioFilePath is deprecated, please use travelAudio instead")]
|
||||
public string travelAudioFilePath;
|
||||
|
||||
/// <summary>
|
||||
/// The audio that will play when travelling in space. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
[Obsolete("travelAudio is deprecated, please use travelAudio instead")]
|
||||
public string travelAudio;
|
||||
|
||||
/// <summary>
|
||||
/// Replace music that plays globally
|
||||
/// </summary>
|
||||
public GlobalMusicModule GlobalMusic;
|
||||
|
||||
/// <summary>
|
||||
/// Configure warping to this system with the vessel
|
||||
/// </summary>
|
||||
@ -117,6 +134,11 @@ namespace NewHorizons.External.Configs
|
||||
/// </summary>
|
||||
public string[] initialReveal;
|
||||
|
||||
/// <summary>
|
||||
/// The planet to focus on when entering the ship log for the first time in a loop. If not set this will be the planet at navtigation position (1, 0)
|
||||
/// </summary>
|
||||
public string shipLogStartingPlanetID;
|
||||
|
||||
/// <summary>
|
||||
/// List colors of curiosity entries
|
||||
/// </summary>
|
||||
@ -187,6 +209,45 @@ namespace NewHorizons.External.Configs
|
||||
public string backPath;
|
||||
}
|
||||
|
||||
[JsonObject]
|
||||
public class GlobalMusicModule
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio that will play when travelling in space. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
public string travelAudio;
|
||||
|
||||
/// <summary>
|
||||
/// The audio that will play right before the loop ends. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
public string endTimesAudio;
|
||||
|
||||
/// <summary>
|
||||
/// The audio that will play right before the loop ends while inside the dreamworld. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
public string endTimesDreamAudio;
|
||||
|
||||
/// <summary>
|
||||
/// The audio that will play when travelling through a bramble dimension. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
public string brambleDimensionAudio;
|
||||
|
||||
/// <summary>
|
||||
/// The audio that will play when you leave the ash twin project after taking out the advanced warp core. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
public string finalEndTimesIntroAudio;
|
||||
|
||||
/// <summary>
|
||||
/// The audio that will loop after the final end times intro. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
public string finalEndTimesLoopAudio;
|
||||
|
||||
/// <summary>
|
||||
/// The audio that will loop after the final end times intro while inside a bramble dimension. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
public string finalEndTimesBrambleDimensionAudio;
|
||||
}
|
||||
|
||||
[JsonObject]
|
||||
public class VesselModule
|
||||
{
|
||||
@ -278,7 +339,6 @@ namespace NewHorizons.External.Configs
|
||||
// If current one is null take the other
|
||||
factRequiredForWarp = string.IsNullOrEmpty(factRequiredForWarp) ? otherConfig.factRequiredForWarp : factRequiredForWarp;
|
||||
Skybox = Skybox == null ? otherConfig.Skybox : Skybox;
|
||||
travelAudio = string.IsNullOrEmpty(travelAudio) ? otherConfig.travelAudio : travelAudio;
|
||||
|
||||
// False by default so if one is true go true
|
||||
mapRestricted = mapRestricted || otherConfig.mapRestricted;
|
||||
@ -297,6 +357,21 @@ namespace NewHorizons.External.Configs
|
||||
Vessel ??= otherConfig.Vessel;
|
||||
}
|
||||
|
||||
if (GlobalMusic != null && otherConfig.GlobalMusic != null)
|
||||
{
|
||||
GlobalMusic.travelAudio = string.IsNullOrEmpty(GlobalMusic.travelAudio) ? otherConfig.GlobalMusic.travelAudio : GlobalMusic.travelAudio;
|
||||
GlobalMusic.endTimesAudio = string.IsNullOrEmpty(GlobalMusic.endTimesAudio) ? otherConfig.GlobalMusic.endTimesAudio : GlobalMusic.endTimesAudio;
|
||||
GlobalMusic.endTimesDreamAudio = string.IsNullOrEmpty(GlobalMusic.endTimesDreamAudio) ? otherConfig.GlobalMusic.endTimesDreamAudio : GlobalMusic.endTimesDreamAudio;
|
||||
GlobalMusic.brambleDimensionAudio = string.IsNullOrEmpty(GlobalMusic.brambleDimensionAudio) ? otherConfig.GlobalMusic.brambleDimensionAudio : GlobalMusic.brambleDimensionAudio;
|
||||
GlobalMusic.finalEndTimesIntroAudio = string.IsNullOrEmpty(GlobalMusic.finalEndTimesIntroAudio) ? otherConfig.GlobalMusic.finalEndTimesIntroAudio : GlobalMusic.finalEndTimesIntroAudio;
|
||||
GlobalMusic.finalEndTimesLoopAudio = string.IsNullOrEmpty(GlobalMusic.finalEndTimesLoopAudio) ? otherConfig.GlobalMusic.finalEndTimesLoopAudio : GlobalMusic.finalEndTimesLoopAudio;
|
||||
GlobalMusic.finalEndTimesBrambleDimensionAudio = string.IsNullOrEmpty(GlobalMusic.finalEndTimesBrambleDimensionAudio) ? otherConfig.GlobalMusic.finalEndTimesBrambleDimensionAudio : GlobalMusic.finalEndTimesBrambleDimensionAudio;
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalMusic ??= otherConfig.GlobalMusic;
|
||||
}
|
||||
|
||||
entryPositions = Concatenate(entryPositions, otherConfig.entryPositions);
|
||||
curiosities = Concatenate(curiosities, otherConfig.curiosities);
|
||||
initialReveal = Concatenate(initialReveal, otherConfig.initialReveal);
|
||||
@ -314,6 +389,11 @@ namespace NewHorizons.External.Configs
|
||||
#pragma warning disable 612, 618
|
||||
if (!string.IsNullOrEmpty(travelAudioClip)) travelAudio = travelAudioClip;
|
||||
if (!string.IsNullOrEmpty(travelAudioFilePath)) travelAudio = travelAudioFilePath;
|
||||
if (!string.IsNullOrEmpty(travelAudio))
|
||||
{
|
||||
if (GlobalMusic == null) GlobalMusic = new GlobalMusicModule();
|
||||
if (string.IsNullOrEmpty(GlobalMusic.travelAudio)) GlobalMusic.travelAudio = travelAudio;
|
||||
}
|
||||
if (coords != null || vesselPosition != null || vesselRotation != null || warpExitPosition != null || warpExitRotation != null)
|
||||
{
|
||||
if (Vessel == null)
|
||||
@ -348,6 +428,10 @@ namespace NewHorizons.External.Configs
|
||||
Vessel.warpExit.attachToVessel = true;
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(factRequiredToExitViaWarpDrive))
|
||||
{
|
||||
canExitViaWarpDrive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
NewHorizons/External/Modules/BaseModule.cs
vendored
8
NewHorizons/External/Modules/BaseModule.cs
vendored
@ -36,11 +36,6 @@ namespace NewHorizons.External.Modules
|
||||
/// </summary>
|
||||
public float groundSize;
|
||||
|
||||
/// <summary>
|
||||
/// If the body should have a marker on the map screen.
|
||||
/// </summary>
|
||||
public bool hasMapMarker;
|
||||
|
||||
/// <summary>
|
||||
/// Can this planet survive entering a star?
|
||||
/// </summary>
|
||||
@ -108,6 +103,9 @@ namespace NewHorizons.External.Modules
|
||||
[Obsolete("AmbientLight is deprecated, please use AmbientLightModule instead")]
|
||||
public float ambientLight;
|
||||
|
||||
[Obsolete("HasMapMarker is deprecated, please use MapMarkerModule instead")]
|
||||
public bool hasMapMarker;
|
||||
|
||||
[Obsolete("HasReferenceFrame is deprecated, please use ReferenceModule instead")]
|
||||
[DefaultValue(true)] public bool hasReferenceFrame = true;
|
||||
|
||||
|
||||
26
NewHorizons/External/Modules/GeneralPropInfo.cs
vendored
26
NewHorizons/External/Modules/GeneralPropInfo.cs
vendored
@ -5,27 +5,31 @@ using Newtonsoft.Json;
|
||||
namespace NewHorizons.External.Modules
|
||||
{
|
||||
[JsonObject]
|
||||
public abstract class GeneralPointPropInfo
|
||||
public abstract class BasePropInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The relative path from the planet to the parent of this object. Optional (will default to the root sector).
|
||||
/// </summary>
|
||||
public string parentPath;
|
||||
|
||||
/// <summary>
|
||||
/// An optional rename of this object
|
||||
/// </summary>
|
||||
public string rename;
|
||||
}
|
||||
|
||||
[JsonObject]
|
||||
public abstract class GeneralPointPropInfo : BasePropInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Position of the object
|
||||
/// </summary>
|
||||
public MVector3 position;
|
||||
|
||||
/// <summary>
|
||||
/// The relative path from the planet to the parent of this object. Optional (will default to the root sector).
|
||||
/// </summary>
|
||||
public string parentPath;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the positional and rotational coordinates are relative to parent instead of the root planet object.
|
||||
/// </summary>
|
||||
public bool isRelativeToParent;
|
||||
|
||||
/// <summary>
|
||||
/// An optional rename of this object
|
||||
/// </summary>
|
||||
public string rename;
|
||||
}
|
||||
|
||||
[JsonObject]
|
||||
|
||||
25
NewHorizons/External/Modules/MapMarkerModule.cs
vendored
Normal file
25
NewHorizons/External/Modules/MapMarkerModule.cs
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
using System.ComponentModel;
|
||||
using NewHorizons.External.SerializableData;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NewHorizons.External.Modules
|
||||
{
|
||||
[JsonObject]
|
||||
public class MapMarkerModule
|
||||
{
|
||||
/// <summary>
|
||||
/// If the body should have a marker on the map screen.
|
||||
/// </summary>
|
||||
public bool enabled;
|
||||
|
||||
/// <summary>
|
||||
/// Lowest distance away from the body that the marker can be shown. This is automatically set to 0 for all bodies except focal points where it is 5,000.
|
||||
/// </summary>
|
||||
public float minDisplayDistanceOverride = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Highest distance away from the body that the marker can be shown. For planets and focal points the automatic value is 50,000. Moons and planets in focal points are 5,000. Stars are 1E+10 (10,000,000,000).
|
||||
/// </summary>
|
||||
public float maxDisplayDistanceOverride = -1;
|
||||
}
|
||||
}
|
||||
@ -54,7 +54,9 @@ namespace NewHorizons.External.Modules.Props
|
||||
public string quantumGroupID;
|
||||
|
||||
/// <summary>
|
||||
/// Should this detail stay loaded even if you're outside the sector (good for very large props)
|
||||
/// Should this detail stay loaded (visible and collideable) even if you're outside the sector (good for very large props)?
|
||||
/// Also makes this detail visible on the map.
|
||||
/// Most logic/behavior scripts will still only work inside the sector, as most of those scripts break if a sector is not provided.
|
||||
/// </summary>
|
||||
public bool keepLoaded;
|
||||
|
||||
|
||||
32
NewHorizons/External/Modules/Props/Dialogue/AttentionPointInfo.cs
vendored
Normal file
32
NewHorizons/External/Modules/Props/Dialogue/AttentionPointInfo.cs
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
using NewHorizons.External.SerializableData;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace NewHorizons.External.Modules.Props.Dialogue
|
||||
{
|
||||
[JsonObject]
|
||||
public class AttentionPointInfo : GeneralPointPropInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// An additional offset to apply to apply when the camera looks at this attention point.
|
||||
/// </summary>
|
||||
public MVector3 offset;
|
||||
}
|
||||
|
||||
[JsonObject]
|
||||
public class SwappedAttentionPointInfo : AttentionPointInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the dialogue node to activate this attention point for. If null or blank, activates for every node.
|
||||
/// </summary>
|
||||
public string dialogueNode;
|
||||
/// <summary>
|
||||
/// The index of the page in the current dialogue node to activate this attention point for, if the node has multiple pages.
|
||||
/// </summary>
|
||||
public int dialoguePage;
|
||||
/// <summary>
|
||||
/// The easing factor which determines how 'snappy' the camera is when looking at the attention point.
|
||||
/// </summary>
|
||||
[DefaultValue(1)] public float lookEasing = 1f;
|
||||
}
|
||||
}
|
||||
@ -31,6 +31,11 @@ namespace NewHorizons.External.Modules.Props.Dialogue
|
||||
/// </summary>
|
||||
public string pathToAnimController;
|
||||
|
||||
/// <summary>
|
||||
/// If this dialogue is adding to existing character dialogue, put a path to the game object with the dialogue on it here
|
||||
/// </summary>
|
||||
public string pathToExistingDialogue;
|
||||
|
||||
/// <summary>
|
||||
/// Radius of the spherical collision volume where you get the "talk to" prompt when looking at. If you use a
|
||||
/// remoteTrigger, you can set this to 0 to make the dialogue only trigger remotely.
|
||||
@ -42,6 +47,16 @@ namespace NewHorizons.External.Modules.Props.Dialogue
|
||||
/// </summary>
|
||||
[DefaultValue(2f)] public float range = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// The point that the camera looks at when dialogue advances.
|
||||
/// </summary>
|
||||
public AttentionPointInfo attentionPoint;
|
||||
|
||||
/// <summary>
|
||||
/// Additional points that the camera looks at when dialogue advances through specific dialogue nodes and pages.
|
||||
/// </summary>
|
||||
public SwappedAttentionPointInfo[] swappedAttentionPoints;
|
||||
|
||||
/// <summary>
|
||||
/// Allows you to trigger dialogue from a distance when you walk into an area.
|
||||
/// </summary>
|
||||
|
||||
@ -21,6 +21,28 @@ namespace NewHorizons.External.Modules.Props.EchoesOfTheEye
|
||||
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum SlideReelType
|
||||
{
|
||||
[EnumMember(Value = @"sixSlides")] SixSlides = 6,
|
||||
|
||||
[EnumMember(Value = @"sevenSlides")] SevenSlides = 7,
|
||||
|
||||
[EnumMember(Value = @"eightSlides")] EightSlides = 8,
|
||||
|
||||
[EnumMember(Value = @"whole")] Whole = 9,
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum SlideReelCondition
|
||||
{
|
||||
[EnumMember(Value = @"antique")] Antique = 0,
|
||||
|
||||
[EnumMember(Value = @"pristine")] Pristine = 1,
|
||||
|
||||
[EnumMember(Value = @"rusted")] Rusted = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The ship log facts revealed after finishing this slide reel.
|
||||
/// </summary>
|
||||
@ -43,6 +65,16 @@ namespace NewHorizons.External.Modules.Props.EchoesOfTheEye
|
||||
/// The type of object this is.
|
||||
/// </summary>
|
||||
[DefaultValue("slideReel")] public SlideShowType type = SlideShowType.SlideReel;
|
||||
|
||||
/// <summary>
|
||||
/// Exclusive to the slide reel type. Model/mesh of the reel. Each model has a different number of slides on it. Whole has 7 slides but a full ring like 8.
|
||||
/// </summary>
|
||||
[DefaultValue("sevenSlides")] public SlideReelType reelModel = SlideReelType.SevenSlides;
|
||||
|
||||
/// <summary>
|
||||
/// Exclusive to the slide reel type. Condition/material of the reel. Antique is the Stranger, Pristine is the Dreamworld, Rusted is a burned reel.
|
||||
/// </summary>
|
||||
[DefaultValue("antique")] public SlideReelCondition reelCondition = SlideReelCondition.Antique;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -84,5 +84,12 @@ namespace NewHorizons.External.Modules.Props.EchoesOfTheEye
|
||||
/// Set this to include ship log entry module. Base game default is "".
|
||||
/// </summary>
|
||||
public string reveal;
|
||||
|
||||
// SlideRotationModule
|
||||
|
||||
/// <summary>
|
||||
/// Exclusive to slide reels. Whether this slide should rotate the reel item while inside a projector.
|
||||
/// </summary>
|
||||
[DefaultValue(true)] public bool rotate = true;
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ namespace NewHorizons.External.Modules.Props.Item
|
||||
/// </summary>
|
||||
public string name;
|
||||
/// <summary>
|
||||
/// The type of the item, which determines its orientation when held and what sockets it fits into. This can be a custom string, or a vanilla ItemType (Scroll, WarpCode, SharedStone, ConversationStone, Lantern, SlideReel, DreamLantern, or VisionTorch). Defaults to the item name.
|
||||
/// The type of the item, which determines its orientation when held and what sockets it fits into. This can be a custom string, or a vanilla ItemType (Scroll, WarpCore, SharedStone, ConversationStone, Lantern, SlideReel, DreamLantern, or VisionTorch). Defaults to the item name.
|
||||
/// </summary>
|
||||
public string itemType;
|
||||
/// <summary>
|
||||
@ -27,6 +27,11 @@ namespace NewHorizons.External.Modules.Props.Item
|
||||
/// </summary>
|
||||
[DefaultValue(2f)] public float interactRange = 2f;
|
||||
/// <summary>
|
||||
/// The radius that the added sphere collider will use for collision and hover detection.
|
||||
/// If there's already a collider on the detail, you can make this 0.
|
||||
/// </summary>
|
||||
[DefaultValue(0.5f)] public float colliderRadius = 0.5f;
|
||||
/// <summary>
|
||||
/// Whether the item can be dropped. Defaults to true.
|
||||
/// </summary>
|
||||
[DefaultValue(true)] public bool droppable = true;
|
||||
@ -39,6 +44,22 @@ namespace NewHorizons.External.Modules.Props.Item
|
||||
/// </summary>
|
||||
public MVector3 dropNormal;
|
||||
/// <summary>
|
||||
/// A relative offset to apply to the item's position when holding it. The initial position varies for vanilla item types.
|
||||
/// </summary>
|
||||
public MVector3 holdOffset;
|
||||
/// <summary>
|
||||
/// A relative offset to apply to the item's rotation when holding it.
|
||||
/// </summary>
|
||||
public MVector3 holdRotation;
|
||||
/// <summary>
|
||||
/// A relative offset to apply to the item's position when placing it into a socket.
|
||||
/// </summary>
|
||||
public MVector3 socketOffset;
|
||||
/// <summary>
|
||||
/// A relative offset to apply to the item's rotation when placing it into a socket.
|
||||
/// </summary>
|
||||
public MVector3 socketRotation;
|
||||
/// <summary>
|
||||
/// The audio to play when this item is picked up. Only applies to custom/non-vanilla item types.
|
||||
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||
/// </summary>
|
||||
|
||||
@ -3,7 +3,7 @@ using Newtonsoft.Json;
|
||||
namespace NewHorizons.External.Modules.Props.Remote
|
||||
{
|
||||
[JsonObject]
|
||||
public class StoneInfo : GeneralPropInfo
|
||||
public class ProjectionStoneInfo : GeneralPropInfo
|
||||
{
|
||||
|
||||
}
|
||||
@ -23,11 +23,11 @@ namespace NewHorizons.External.Modules.Props.Remote
|
||||
/// <summary>
|
||||
/// Camera platform that the stones can project to and from
|
||||
/// </summary>
|
||||
public PlatformInfo platform;
|
||||
public RemotePlatformInfo platform;
|
||||
|
||||
/// <summary>
|
||||
/// Projection stones
|
||||
/// </summary>
|
||||
public StoneInfo[] stones;
|
||||
public ProjectionStoneInfo[] stones;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ using System.ComponentModel;
|
||||
namespace NewHorizons.External.Modules.Props.Remote
|
||||
{
|
||||
[JsonObject]
|
||||
public class PlatformInfo : GeneralPropInfo
|
||||
public class RemotePlatformInfo : GeneralPropInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// A ship log fact to reveal when the platform is connected to.
|
||||
@ -66,5 +66,10 @@ namespace NewHorizons.External.Modules.Props
|
||||
/// Should this detail stay loaded even if you're outside the sector (good for very large props)
|
||||
/// </summary>
|
||||
public bool keepLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// The relative path from the planet to the parent of this object. Optional (will default to the root sector). This parent should be at the position where you'd like to scatter (which would usually be zero).
|
||||
/// </summary>
|
||||
public string parentPath;
|
||||
}
|
||||
}
|
||||
|
||||
19
NewHorizons/External/NewHorizonBody.cs
vendored
19
NewHorizons/External/NewHorizonBody.cs
vendored
@ -28,11 +28,20 @@ namespace NewHorizons.External
|
||||
|
||||
public bool RequiresDLC()
|
||||
{
|
||||
var detailPaths = Config.Props.details.Select(x => x.path);
|
||||
return Config.Cloak != null
|
||||
|| Config.Props?.rafts != null
|
||||
|| Config.Props?.slideShows != null
|
||||
|| detailPaths.Any(x => x.StartsWith("Ringworld") || x.StartsWith("Dreamworld"));
|
||||
try
|
||||
{
|
||||
var detailPaths = Config?.Props?.details?.Select(x => x.path) ?? Array.Empty<string>();
|
||||
return Config?.Cloak != null
|
||||
|| Config?.Props?.rafts != null
|
||||
|| Config?.Props?.slideShows != null
|
||||
|| detailPaths.Any(x => x.StartsWith("RingWorld_Body") || x.StartsWith("DreamWorld_Body"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
NHLogger.LogWarning($"Failed to check if {Mod.ModHelper.Manifest.Name} requires the DLC");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region Cache
|
||||
|
||||
17
NewHorizons/External/NewHorizonsData.cs
vendored
17
NewHorizons/External/NewHorizonsData.cs
vendored
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NewHorizons.Builder.Props.Audio;
|
||||
using NewHorizons.Utility.OWML;
|
||||
|
||||
namespace NewHorizons.External
|
||||
@ -124,7 +126,6 @@ namespace NewHorizons.External
|
||||
if (!KnowsFrequency(frequency))
|
||||
{
|
||||
_activeProfile.KnownFrequencies.Add(frequency);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,13 +135,12 @@ namespace NewHorizons.External
|
||||
if (KnowsFrequency(frequency))
|
||||
{
|
||||
_activeProfile.KnownFrequencies.Remove(frequency);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool KnowsMultipleFrequencies()
|
||||
{
|
||||
return _activeProfile != null && _activeProfile.KnownFrequencies.Count > 0;
|
||||
return _activeProfile?.KnownFrequencies != null && _activeProfile.KnownFrequencies.Count(SignalBuilder.IsFrequencyInUse) > 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -159,7 +159,6 @@ namespace NewHorizons.External
|
||||
if (!KnowsSignal(signal))
|
||||
{
|
||||
_activeProfile.KnownSignals.Add(signal);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +169,6 @@ namespace NewHorizons.External
|
||||
public static void AddNewlyRevealedFactID(string id)
|
||||
{
|
||||
_activeProfile?.NewlyRevealedFactIDs.Add(id);
|
||||
Save();
|
||||
}
|
||||
|
||||
public static List<string> GetNewlyRevealedFactIDs()
|
||||
@ -181,7 +179,6 @@ namespace NewHorizons.External
|
||||
public static void ClearNewlyRevealedFactIDs()
|
||||
{
|
||||
_activeProfile?.NewlyRevealedFactIDs.Clear();
|
||||
Save();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -190,8 +187,11 @@ namespace NewHorizons.External
|
||||
|
||||
public static void ReadOneTimePopup(string id)
|
||||
{
|
||||
_activeProfile?.PopupsRead.Add(id);
|
||||
Save();
|
||||
// else it re-adds it each time
|
||||
if (_activeProfile != null && !_activeProfile.PopupsRead.Contains(id))
|
||||
{
|
||||
_activeProfile.PopupsRead.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasReadOneTimePopup(string id)
|
||||
@ -208,7 +208,6 @@ namespace NewHorizons.External
|
||||
{
|
||||
if (name == CharacterDialogueTree.RECORDING_NAME || name == CharacterDialogueTree.SIGN_NAME) return;
|
||||
_activeProfile?.CharactersTalkedTo.SafeAdd(name);
|
||||
Save();
|
||||
}
|
||||
|
||||
public static bool HasTalkedToFiveCharacters()
|
||||
|
||||
7
NewHorizons/External/NewHorizonsSystem.cs
vendored
7
NewHorizons/External/NewHorizonsSystem.cs
vendored
@ -1,6 +1,7 @@
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.External.Modules;
|
||||
using OWML.Common;
|
||||
using System.Linq;
|
||||
|
||||
namespace NewHorizons.External
|
||||
{
|
||||
@ -19,6 +20,12 @@ namespace NewHorizons.External
|
||||
Config = config;
|
||||
RelativePath = relativePath;
|
||||
Mod = mod;
|
||||
|
||||
// Backwards compat
|
||||
if (new string[] { "2walker2.OogaBooga", "2walker2.EndingIfYouWarpHereYouAreMean", "FeldsparSystem" }.Contains(uniqueID))
|
||||
{
|
||||
config.canExitViaWarpDrive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
#region
|
||||
|
||||
using NewHorizons.Utility.DebugTools.Menu;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
#endregion
|
||||
@ -26,6 +29,11 @@ namespace NewHorizons.External.SerializableData
|
||||
|
||||
public static implicit operator Vector2(MVector2 vec)
|
||||
{
|
||||
if (vec == null)
|
||||
{
|
||||
NHLogger.LogWarning($"Null MVector2 can't be turned into a non-nullable Vector2, returning Vector2.zero - {Environment.StackTrace}");
|
||||
return Vector2.zero;
|
||||
}
|
||||
return new Vector2(vec.x, vec.y);
|
||||
}
|
||||
}
|
||||
|
||||
63
NewHorizons/Handlers/EyeDetailCacher.cs
Normal file
63
NewHorizons/Handlers/EyeDetailCacher.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using System.Linq;
|
||||
|
||||
namespace NewHorizons.Handlers;
|
||||
|
||||
public static class EyeDetailCacher
|
||||
{
|
||||
public static bool IsInitialized;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
if (IsInitialized) return;
|
||||
|
||||
SearchUtilities.ClearDontDestroyOnLoadCache();
|
||||
|
||||
IsInitialized = true;
|
||||
|
||||
foreach (var body in Main.BodyDict["EyeOfTheUniverse"])
|
||||
{
|
||||
NHLogger.LogVerbose($"{nameof(EyeDetailCacher)}: {body.Config.name}");
|
||||
if (body.Config?.Props?.details != null)
|
||||
{
|
||||
foreach (var detail in body.Config.Props.details)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(detail.assetBundle)) continue;
|
||||
|
||||
AddPathToCache(detail.path);
|
||||
}
|
||||
}
|
||||
|
||||
if (body.Config?.Props?.scatter != null)
|
||||
{
|
||||
foreach (var scatter in body.Config.Props.scatter)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(scatter.assetBundle)) continue;
|
||||
|
||||
AddPathToCache(scatter.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddPathToCache(string path)
|
||||
{
|
||||
NHLogger.LogVerbose($"{nameof(EyeDetailCacher)}: {path}");
|
||||
|
||||
if (string.IsNullOrEmpty(path)) return;
|
||||
|
||||
var planet = path.Contains('/') ? path.Split('/').First() : string.Empty;
|
||||
|
||||
if (planet != "EyeOfTheUniverse_Body" && planet != "Vessel_Body")
|
||||
{
|
||||
NHLogger.LogVerbose($"{nameof(EyeDetailCacher)}: Looking for {path}");
|
||||
var obj = SearchUtilities.Find(path);
|
||||
if (obj != null)
|
||||
{
|
||||
NHLogger.LogVerbose($"{nameof(EyeDetailCacher)}: Added solar system asset to dont destroy on load cache for eye: {path}");
|
||||
SearchUtilities.AddToDontDestroyOnLoadCache(path, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,10 @@ using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Handlers
|
||||
{
|
||||
/// <summary>
|
||||
/// copied from LoadManager.
|
||||
/// exists so we can do things after the fade without patching.
|
||||
/// </summary>
|
||||
public static class FadeHandler
|
||||
{
|
||||
public static void FadeOut(float length) => Delay.StartCoroutine(FadeOutCoroutine(length));
|
||||
@ -17,11 +21,14 @@ namespace NewHorizons.Handlers
|
||||
|
||||
while (Time.unscaledTime < endTime)
|
||||
{
|
||||
LoadManager.s_instance._fadeImage.color = Color.Lerp(Color.clear, Color.black, (Time.unscaledTime - startTime) / length);
|
||||
var t = Mathf.Clamp01((Time.unscaledTime - startTime) / length);
|
||||
LoadManager.s_instance._fadeImage.color = Color.Lerp(Color.clear, Color.black, t);
|
||||
AudioListener.volume = 1f - t;
|
||||
yield return new WaitForEndOfFrame();
|
||||
}
|
||||
|
||||
LoadManager.s_instance._fadeImage.color = Color.black;
|
||||
AudioListener.volume = 0;
|
||||
yield return new WaitForEndOfFrame();
|
||||
}
|
||||
|
||||
|
||||
@ -3,15 +3,19 @@ using NewHorizons.Builder.Body;
|
||||
using NewHorizons.Builder.General;
|
||||
using NewHorizons.Builder.Orbital;
|
||||
using NewHorizons.Builder.Props;
|
||||
using NewHorizons.Builder.ShipLog;
|
||||
using NewHorizons.Builder.Volumes;
|
||||
using NewHorizons.Components.Orbital;
|
||||
using NewHorizons.Components.Quantum;
|
||||
using NewHorizons.Components.Stars;
|
||||
using NewHorizons.External;
|
||||
using NewHorizons.OtherMods.OWRichPresence;
|
||||
using NewHorizons.Streaming;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using NewHorizons.Utility.OuterWilds;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using Newtonsoft.Json;
|
||||
using OWML.ModHelper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -345,6 +349,13 @@ namespace NewHorizons.Handlers
|
||||
// Do stuff that's shared between generating new planets and updating old ones
|
||||
go = SharedGenerateBody(body, go, sector, rb);
|
||||
|
||||
if (body.Config.ShipLog?.mapMode != null)
|
||||
{
|
||||
MapModeBuilder.TryReplaceExistingMapModeIcon(body, body.Mod as ModBehaviour, body.Config.ShipLog.mapMode);
|
||||
}
|
||||
|
||||
body.Object = go;
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
@ -367,12 +378,12 @@ namespace NewHorizons.Handlers
|
||||
go.SetActive(false);
|
||||
|
||||
body.Config.Base.showMinimap = false;
|
||||
body.Config.Base.hasMapMarker = false;
|
||||
body.Config.MapMarker.enabled = false;
|
||||
|
||||
const float sphereOfInfluence = 2000f;
|
||||
|
||||
var owRigidBody = RigidBodyBuilder.Make(go, sphereOfInfluence, body.Config);
|
||||
var ao = AstroObjectBuilder.Make(go, null, body.Config, false);
|
||||
var ao = AstroObjectBuilder.Make(go, null, body, false);
|
||||
|
||||
var sector = SectorBuilder.Make(go, owRigidBody, sphereOfInfluence);
|
||||
ao._rootSector = sector;
|
||||
@ -448,7 +459,7 @@ namespace NewHorizons.Handlers
|
||||
var sphereOfInfluence = GetSphereOfInfluence(body);
|
||||
|
||||
var owRigidBody = RigidBodyBuilder.Make(go, sphereOfInfluence, body.Config);
|
||||
var ao = AstroObjectBuilder.Make(go, primaryBody, body.Config, false);
|
||||
var ao = AstroObjectBuilder.Make(go, primaryBody, body, false);
|
||||
|
||||
var sector = SectorBuilder.Make(go, owRigidBody, sphereOfInfluence * 2f);
|
||||
ao._rootSector = sector;
|
||||
@ -460,7 +471,7 @@ namespace NewHorizons.Handlers
|
||||
|
||||
RFVolumeBuilder.Make(go, owRigidBody, sphereOfInfluence, body.Config.ReferenceFrame);
|
||||
|
||||
if (body.Config.Base.hasMapMarker)
|
||||
if (body.Config.MapMarker.enabled)
|
||||
{
|
||||
MarkerBuilder.Make(go, body.Config.name, body.Config);
|
||||
}
|
||||
@ -791,7 +802,7 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
|
||||
// Just destroy the existing AO after copying everything over
|
||||
var newAO = AstroObjectBuilder.Make(go, primary, body.Config, true);
|
||||
var newAO = AstroObjectBuilder.Make(go, primary, body, true);
|
||||
newAO._gravityVolume = ao._gravityVolume;
|
||||
newAO._moon = ao._moon;
|
||||
newAO._name = ao._name;
|
||||
@ -931,7 +942,7 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
|
||||
// Uses the ratio of the interlopers furthest point to what the base game considers the edge of the solar system
|
||||
var distanceToCenter = go.transform.position.magnitude * (24000 / 30000f);
|
||||
var distanceToCenter = go.transform.position.magnitude / (24000 / 30000f);
|
||||
if (distanceToCenter > SolarSystemRadius)
|
||||
{
|
||||
SolarSystemRadius = distanceToCenter;
|
||||
|
||||
@ -126,11 +126,11 @@ namespace NewHorizons.Handlers
|
||||
|
||||
private static bool DetermineIfChildOfFocal(NewHorizonsBody body, FocalPointNode node)
|
||||
{
|
||||
var name = body.Config.name.ToLower();
|
||||
var primary = (body.Config.Orbit?.primaryBody ?? "").ToLower();
|
||||
var primaryName = node.primary.body.Config.name.ToLower();
|
||||
var secondaryName = node.secondary.body.Config.name.ToLower();
|
||||
return name != primaryName && name != secondaryName && (primary == node.body.Config.name.ToLower() || primary == primaryName || primary == secondaryName);
|
||||
var name = body.Config.name.ToLowerInvariant();
|
||||
var primary = (body.Config.Orbit?.primaryBody ?? "").ToLowerInvariant();
|
||||
var primaryName = node.primary.body.Config.name.ToLowerInvariant();
|
||||
var secondaryName = node.secondary.body.Config.name.ToLowerInvariant();
|
||||
return name != primaryName && name != secondaryName && (primary == node.body.Config.name.ToLowerInvariant() || primary == primaryName || primary == secondaryName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -115,6 +115,17 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
// For some reason none of this seems to apply to the Player.
|
||||
// If somebody ever makes a sound volume thats somehow always applying to the player tho then itd probably be this
|
||||
|
||||
// Sometimes the ship isn't added to the volumes it's meant to now be in
|
||||
foreach (var volume in SpawnPointBuilder.ShipSpawn.GetAttachedOWRigidbody().GetComponentsInChildren<EffectVolume>())
|
||||
{
|
||||
if (volume.GetOWTriggerVolume().GetPenetrationDistance(ship.transform.position) > 0)
|
||||
{
|
||||
// Add ship to volume
|
||||
// If it's already tracking it it will complain here but thats fine
|
||||
volume.GetOWTriggerVolume().AddObjectToVolume(Locator.GetShipDetector());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Main.Instance.CurrentStarSystem != "SolarSystem" && !Main.Instance.IsWarpingFromShip)
|
||||
@ -126,30 +137,39 @@ namespace NewHorizons.Handlers
|
||||
|
||||
private static IEnumerator SpawnCoroutine(int length)
|
||||
{
|
||||
FixPlayerVelocity();
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
FixPlayerVelocity();
|
||||
FixPlayerVelocity(false); // dont recenter universe here or else it spams and lags game
|
||||
yield return new WaitForEndOfFrame();
|
||||
}
|
||||
FixPlayerVelocity();
|
||||
|
||||
InvulnerabilityHandler.MakeInvulnerable(false);
|
||||
}
|
||||
|
||||
private static void FixPlayerVelocity()
|
||||
private static void FixPlayerVelocity(bool recenter = true)
|
||||
{
|
||||
var playerBody = SearchUtilities.Find("Player_Body").GetAttachedOWRigidbody();
|
||||
var resources = playerBody.GetComponent<PlayerResources>();
|
||||
|
||||
SpawnBody(playerBody, GetDefaultSpawn());
|
||||
SpawnBody(playerBody, GetDefaultSpawn(), recenter: recenter);
|
||||
|
||||
resources._currentHealth = 100f;
|
||||
}
|
||||
|
||||
public static void SpawnBody(OWRigidbody body, SpawnPoint spawn, Vector3? positionOverride = null)
|
||||
public static void SpawnBody(OWRigidbody body, SpawnPoint spawn, Vector3? positionOverride = null, bool recenter = true)
|
||||
{
|
||||
var pos = positionOverride ?? spawn.transform.position;
|
||||
|
||||
body.WarpToPositionRotation(pos, spawn.transform.rotation);
|
||||
if (recenter)
|
||||
{
|
||||
body.WarpToPositionRotation(pos, spawn.transform.rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
body.transform.SetPositionAndRotation(pos, spawn.transform.rotation);
|
||||
}
|
||||
|
||||
var spawnVelocity = spawn._attachedBody.GetVelocity();
|
||||
var spawnAngularVelocity = spawn._attachedBody.GetPointTangentialVelocity(pos);
|
||||
|
||||
@ -2,6 +2,7 @@ using NewHorizons.Utility.OWML;
|
||||
using OWML.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
||||
namespace NewHorizons.Handlers
|
||||
@ -33,24 +34,34 @@ namespace NewHorizons.Handlers
|
||||
return id.ToString();
|
||||
}
|
||||
|
||||
public static NomaiRemoteCameraPlatform.ID GetPlatformID(string id)
|
||||
public static bool TryGetPlatformID(string id, out NomaiRemoteCameraPlatform.ID platformID)
|
||||
{
|
||||
try
|
||||
{
|
||||
NomaiRemoteCameraPlatform.ID platformID;
|
||||
if (_customPlatformIDs.TryGetValue(id, out platformID) || EnumUtils.TryParse<NomaiRemoteCameraPlatform.ID>(id, out platformID))
|
||||
if (!(_customPlatformIDs.TryGetValue(id, out platformID) || EnumUtils.TryParse<NomaiRemoteCameraPlatform.ID>(id, out platformID)))
|
||||
{
|
||||
return platformID;
|
||||
}
|
||||
else
|
||||
{
|
||||
return AddCustomPlatformID(id);
|
||||
platformID = AddCustomPlatformID(id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NHLogger.LogError($"Couldn't load platform id [{id}]:\n{e}");
|
||||
return NomaiRemoteCameraPlatform.ID.None;
|
||||
platformID = NomaiRemoteCameraPlatform.ID.None;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static NomaiRemoteCameraPlatform.ID GetPlatformID(string id)
|
||||
{
|
||||
NomaiRemoteCameraPlatform.ID platformID = NomaiRemoteCameraPlatform.ID.None;
|
||||
if (_customPlatformIDs.TryGetValue(id, out platformID) || EnumUtils.TryParse<NomaiRemoteCameraPlatform.ID>(id, out platformID))
|
||||
{
|
||||
return platformID;
|
||||
}
|
||||
else
|
||||
{
|
||||
return AddCustomPlatformID(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,9 @@ namespace NewHorizons.Handlers
|
||||
private static Dictionary<string, string> _starSystemToFactID;
|
||||
private static Dictionary<string, string> _factIDToStarSystem;
|
||||
|
||||
private static bool _canExitViaWarpDrive;
|
||||
private static string _factRequiredToExitViaWarpDrive;
|
||||
|
||||
private static NewHorizonsSystem[] _systems;
|
||||
|
||||
public static void Init(NewHorizonsSystem[] systems)
|
||||
@ -56,12 +59,21 @@ namespace NewHorizons.Handlers
|
||||
_starSystemToFactID = new Dictionary<string, string>();
|
||||
_factIDToStarSystem = new Dictionary<string, string>();
|
||||
|
||||
_factRequiredToExitViaWarpDrive = string.Empty;
|
||||
|
||||
foreach (NewHorizonsSystem system in _systems)
|
||||
{
|
||||
if (system.Config.factRequiredForWarp != default)
|
||||
if (system.Config.factRequiredForWarp != default && system.UniqueID != "SolarSystem")
|
||||
{
|
||||
RegisterFactForSystem(system.Config.factRequiredForWarp, system.UniqueID);
|
||||
}
|
||||
|
||||
if (system.UniqueID == Main.Instance.CurrentStarSystem)
|
||||
{
|
||||
_factRequiredToExitViaWarpDrive = system.Config.factRequiredToExitViaWarpDrive;
|
||||
_canExitViaWarpDrive = system.Config.canExitViaWarpDrive || !string.IsNullOrEmpty(_factRequiredToExitViaWarpDrive);
|
||||
NHLogger.LogVerbose($"In system {system.UniqueID} can exit via warp drive? {system.Config.canExitViaWarpDrive} {_canExitViaWarpDrive} {_factRequiredToExitViaWarpDrive}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +100,10 @@ namespace NewHorizons.Handlers
|
||||
/// <returns></returns>
|
||||
public static bool HasUnlockedSystem(string system)
|
||||
{
|
||||
// If warp drive is entirely disabled, then no
|
||||
if (!CanExitViaWarpDrive())
|
||||
return false;
|
||||
|
||||
if (_starSystemToFactID == null || _starSystemToFactID.Count == 0)
|
||||
return true;
|
||||
|
||||
@ -99,6 +115,9 @@ namespace NewHorizons.Handlers
|
||||
return ShipLogHandler.KnowsFact(factID);
|
||||
}
|
||||
|
||||
public static bool CanExitViaWarpDrive() => Main.Instance.CurrentStarSystem == "SolarSystem" || (_canExitViaWarpDrive
|
||||
&& (string.IsNullOrEmpty(_factRequiredToExitViaWarpDrive) || ShipLogHandler.KnowsFact(_factRequiredToExitViaWarpDrive)));
|
||||
|
||||
/// <summary>
|
||||
/// Is it actually a valid warp target
|
||||
/// </summary>
|
||||
@ -113,21 +132,56 @@ namespace NewHorizons.Handlers
|
||||
else if (system.Equals("EyeOfTheUniverse")) canWarpTo = false;
|
||||
else if (config.Spawn?.shipSpawn != null) canWarpTo = true;
|
||||
|
||||
var canEnterViaWarpDrive = Main.SystemDict[system].Config.canEnterViaWarpDrive || system == "SolarSystem";
|
||||
|
||||
var canExitViaWarpDrive = CanExitViaWarpDrive();
|
||||
|
||||
// Make base system always ignore canExitViaWarpDrive
|
||||
if (Main.Instance.CurrentStarSystem == "SolarSystem")
|
||||
canExitViaWarpDrive = true;
|
||||
|
||||
NHLogger.LogVerbose(canEnterViaWarpDrive, canExitViaWarpDrive, system, HasUnlockedSystem(system));
|
||||
|
||||
return canWarpTo
|
||||
&& Main.SystemDict[system].Config.canEnterViaWarpDrive
|
||||
&& canEnterViaWarpDrive
|
||||
&& canExitViaWarpDrive
|
||||
&& system != Main.Instance.CurrentStarSystem
|
||||
&& HasUnlockedSystem(system);
|
||||
}
|
||||
|
||||
public static void OnRevealFact(string factID)
|
||||
{
|
||||
if (_factIDToStarSystem.TryGetValue(factID, out var systemUnlocked))
|
||||
if (!string.IsNullOrEmpty(_factRequiredToExitViaWarpDrive) && factID == _factRequiredToExitViaWarpDrive)
|
||||
{
|
||||
NHLogger.Log($"Just learned [{factID}] and unlocked [{systemUnlocked}]");
|
||||
_canExitViaWarpDrive = true;
|
||||
if (!Main.HasWarpDrive)
|
||||
{
|
||||
Main.Instance.EnableWarpDrive();
|
||||
if (ShipLogStarChartMode != null)
|
||||
ShipLogStarChartMode.AddSystemCard(systemUnlocked);
|
||||
// Add all cards that now work
|
||||
foreach (var starSystem in Main.SystemDict.Keys)
|
||||
{
|
||||
if (CanWarpToSystem(starSystem))
|
||||
{
|
||||
ShipLogStarChartMode.AddSystemCard(starSystem);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogWarning("Warp drive was enabled before learning fact?");
|
||||
}
|
||||
}
|
||||
|
||||
if (_factIDToStarSystem != null && _factIDToStarSystem.TryGetValue(factID, out var systemUnlocked))
|
||||
{
|
||||
var knowsWarpFact = string.IsNullOrEmpty(_factRequiredToExitViaWarpDrive) || ShipLogHandler.KnowsFact(_factRequiredToExitViaWarpDrive);
|
||||
|
||||
NHLogger.Log($"Just learned [{factID}] and unlocked [{systemUnlocked}]");
|
||||
if (!Main.HasWarpDrive && knowsWarpFact)
|
||||
{
|
||||
Main.Instance.EnableWarpDrive();
|
||||
}
|
||||
ShipLogStarChartMode?.AddSystemCard(systemUnlocked);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,11 +11,8 @@ namespace NewHorizons.Handlers
|
||||
{
|
||||
class SubtitlesHandler : MonoBehaviour
|
||||
{
|
||||
public static int SUBTITLE_HEIGHT = 97;
|
||||
public static int SUBTITLE_WIDTH = 669; // nice
|
||||
|
||||
public Graphic graphic;
|
||||
public Image image;
|
||||
public static float SUBTITLE_HEIGHT = 97;
|
||||
public static float SUBTITLE_WIDTH = 669; // nice
|
||||
|
||||
public float fadeSpeed = 0.005f;
|
||||
public float fade = 1;
|
||||
@ -29,13 +26,27 @@ namespace NewHorizons.Handlers
|
||||
public static readonly int PAUSE_TIMER_MAX = 50;
|
||||
public int pauseTimer = PAUSE_TIMER_MAX;
|
||||
|
||||
private Image _subtitleDisplay;
|
||||
private Graphic _graphic;
|
||||
|
||||
private static List<(IModBehaviour mod, string filePath)> _additionalSubtitles = new();
|
||||
|
||||
public static void RegisterAdditionalSubtitle(IModBehaviour mod, string filePath)
|
||||
{
|
||||
_additionalSubtitles.Add((mod, filePath));
|
||||
}
|
||||
|
||||
public void CheckForEOTE()
|
||||
{
|
||||
if (!eoteSubtitleHasBeenInserted)
|
||||
{
|
||||
if (Main.HasDLC)
|
||||
{
|
||||
if (eoteSprite != null) possibleSubtitles.Insert(0, eoteSprite); // ensure that the Echoes of the Eye subtitle always appears first
|
||||
if (eoteSprite != null)
|
||||
{
|
||||
// Don't make it appear first actually because we have mods to display!
|
||||
possibleSubtitles.Add(eoteSprite);
|
||||
}
|
||||
eoteSubtitleHasBeenInserted = true;
|
||||
}
|
||||
}
|
||||
@ -43,27 +54,46 @@ namespace NewHorizons.Handlers
|
||||
|
||||
public void Start()
|
||||
{
|
||||
// We preserve the current image to add it to our custom subtitle
|
||||
// We also need this element to preserve its size
|
||||
GetComponent<CanvasGroup>().alpha = 1;
|
||||
graphic = GetComponent<Graphic>();
|
||||
image = GetComponent<UnityEngine.UI.Image>();
|
||||
|
||||
graphic.enabled = true;
|
||||
image.enabled = true;
|
||||
|
||||
var image = GetComponent<Image>();
|
||||
eoteSprite = image.sprite;
|
||||
image.sprite = null;
|
||||
image.enabled = false;
|
||||
var layout = GetComponent<LayoutElement>();
|
||||
layout.minHeight = SUBTITLE_HEIGHT;
|
||||
|
||||
CheckForEOTE();
|
||||
|
||||
image.sprite = null; // Just in case. I don't know how not having the dlc changes the subtitle game object
|
||||
// We add our subtitles as a child object so that their sizing doesnt shift the layout of the main menu
|
||||
_subtitleDisplay = new GameObject("SubtitleDisplay").AddComponent<Image>();
|
||||
_subtitleDisplay.transform.parent = transform;
|
||||
_subtitleDisplay.transform.localPosition = new Vector3(0, 0, 0);
|
||||
_subtitleDisplay.transform.localScale = new Vector3(0.75f, 0.75f, 0.75f);
|
||||
_graphic = _subtitleDisplay.gameObject.GetAddComponent<Graphic>();
|
||||
_subtitleDisplay.gameObject.GetAddComponent<LayoutElement>().minWidth = SUBTITLE_WIDTH;
|
||||
|
||||
AddSubtitles();
|
||||
}
|
||||
|
||||
private void AddSubtitles()
|
||||
{
|
||||
foreach (var mod in Main.MountedAddons.Where(mod => File.Exists($"{mod.ModHelper.Manifest.ModFolderPath}subtitle.png")))
|
||||
foreach (var mod in Main.MountedAddons)
|
||||
{
|
||||
AddSubtitle(mod, "subtitle.png");
|
||||
if (Main.AddonConfigs.TryGetValue(mod, out var addonConfig) && File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, addonConfig.subtitlePath)))
|
||||
{
|
||||
AddSubtitle(mod, addonConfig.subtitlePath);
|
||||
}
|
||||
// Else default to subtitle.png
|
||||
else if (File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, "subtitle.png")))
|
||||
{
|
||||
AddSubtitle(mod, "subtitle.png");
|
||||
}
|
||||
}
|
||||
foreach (var pair in _additionalSubtitles)
|
||||
{
|
||||
AddSubtitle(pair.mod, pair.filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +104,7 @@ namespace NewHorizons.Handlers
|
||||
var tex = ImageUtilities.GetTexture(mod, filepath, false);
|
||||
if (tex == null) return;
|
||||
|
||||
var sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, SUBTITLE_HEIGHT), new Vector2(0.5f, 0.5f), 100.0f);
|
||||
var sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, Mathf.Max(SUBTITLE_HEIGHT, tex.height)), new Vector2(0.5f, 0.5f), 100.0f);
|
||||
AddSubtitle(sprite);
|
||||
}
|
||||
|
||||
@ -87,12 +117,25 @@ namespace NewHorizons.Handlers
|
||||
{
|
||||
CheckForEOTE();
|
||||
|
||||
if (possibleSubtitles.Count == 0) return;
|
||||
if (possibleSubtitles.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (image.sprite == null) image.sprite = possibleSubtitles[0];
|
||||
_subtitleDisplay.transform.localPosition = new Vector3(0, -36, 0);
|
||||
|
||||
if (_subtitleDisplay.sprite == null)
|
||||
{
|
||||
_subtitleDisplay.sprite = possibleSubtitles[0];
|
||||
// Always call this in case we stop changing subtitles after
|
||||
ChangeSubtitle();
|
||||
}
|
||||
|
||||
// don't fade transition subtitles if there's only one subtitle
|
||||
if (possibleSubtitles.Count <= 1) return;
|
||||
if (possibleSubtitles.Count <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pauseTimer > 0)
|
||||
{
|
||||
@ -103,7 +146,7 @@ namespace NewHorizons.Handlers
|
||||
if (fadingAway)
|
||||
{
|
||||
fade -= fadeSpeed;
|
||||
|
||||
|
||||
if (fade <= 0)
|
||||
{
|
||||
fade = 0;
|
||||
@ -114,7 +157,7 @@ namespace NewHorizons.Handlers
|
||||
else
|
||||
{
|
||||
fade += fadeSpeed;
|
||||
|
||||
|
||||
if (fade >= 1)
|
||||
{
|
||||
fade = 1;
|
||||
@ -123,14 +166,19 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
}
|
||||
|
||||
graphic.color = new Color(1, 1, 1, fade);
|
||||
_graphic.color = new Color(1, 1, 1, fade);
|
||||
}
|
||||
|
||||
public void ChangeSubtitle()
|
||||
{
|
||||
subtitleIndex = (subtitleIndex + 1) % possibleSubtitles.Count;
|
||||
|
||||
image.sprite = possibleSubtitles[subtitleIndex];
|
||||
|
||||
var subtitle = possibleSubtitles[subtitleIndex];
|
||||
_subtitleDisplay.sprite = subtitle;
|
||||
var width = subtitle.texture.width;
|
||||
var height = subtitle.texture.height;
|
||||
var ratio = SUBTITLE_WIDTH / width; // one of these needs to be a float so that compiler doesn't think "oh 2 integers! let's round to nearest whole"
|
||||
_subtitleDisplay.rectTransform.sizeDelta = new Vector2(width, height) * ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ using NewHorizons.Utility.OuterWilds;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
using NewHorizons.OtherMods;
|
||||
using NewHorizons.Components.EOTE;
|
||||
using Epic.OnlineServices.Presence;
|
||||
|
||||
namespace NewHorizons.Handlers
|
||||
{
|
||||
@ -34,7 +36,8 @@ namespace NewHorizons.Handlers
|
||||
if (Main.Instance.CurrentStarSystem == "EyeOfTheUniverse") return;
|
||||
|
||||
// Small mod compat change for StopTime - do nothing if it's enabled
|
||||
if (system.Config.enableTimeLoop && !OtherModUtil.IsEnabled("_nebula.StopTime"))
|
||||
// Do not add our custom time loop controller in the base game system: It will handle itself
|
||||
if (Main.Instance.CurrentStarSystem != "SolarSystem" && system.Config.enableTimeLoop && !OtherModUtil.IsEnabled("_nebula.StopTime"))
|
||||
{
|
||||
var timeLoopController = new GameObject("TimeLoopController");
|
||||
timeLoopController.AddComponent<TimeLoopController>();
|
||||
@ -45,9 +48,52 @@ namespace NewHorizons.Handlers
|
||||
TimeLoopUtilities.SetLoopDuration(system.Config.loopDuration);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(system.Config.travelAudio))
|
||||
if (system.Config.GlobalMusic != null)
|
||||
{
|
||||
Delay.FireOnNextUpdate(() => AudioUtilities.SetAudioClip(Locator.GetGlobalMusicController()._travelSource, system.Config.travelAudio, system.Mod));
|
||||
if (!string.IsNullOrEmpty(system.Config.GlobalMusic.travelAudio))
|
||||
{
|
||||
var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.travelAudio, system.Mod);
|
||||
Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._travelSource.AssignAudioLibraryClip(audioType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(system.Config.GlobalMusic.endTimesAudio))
|
||||
{
|
||||
var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.endTimesAudio, system.Mod);
|
||||
Delay.FireOnNextUpdate(() => {
|
||||
Locator.GetGlobalMusicController().gameObject.GetAddComponent<DreamWorldEndTimes>().SetEndTimesAudio(audioType);
|
||||
Locator.GetGlobalMusicController()._endTimesSource.AssignAudioLibraryClip(audioType);
|
||||
});
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(system.Config.GlobalMusic.endTimesDreamAudio))
|
||||
{
|
||||
var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.endTimesDreamAudio, system.Mod);
|
||||
Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController().gameObject.GetAddComponent<DreamWorldEndTimes>().SetEndTimesDreamAudio(audioType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(system.Config.GlobalMusic.brambleDimensionAudio))
|
||||
{
|
||||
var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.brambleDimensionAudio, system.Mod);
|
||||
Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._darkBrambleSource.AssignAudioLibraryClip(audioType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(system.Config.GlobalMusic.finalEndTimesIntroAudio))
|
||||
{
|
||||
var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.finalEndTimesIntroAudio, system.Mod);
|
||||
Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._finalEndTimesIntroSource.AssignAudioLibraryClip(audioType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(system.Config.GlobalMusic.finalEndTimesLoopAudio))
|
||||
{
|
||||
var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.finalEndTimesLoopAudio, system.Mod);
|
||||
Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._finalEndTimesLoopSource.AssignAudioLibraryClip(audioType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(system.Config.GlobalMusic.finalEndTimesBrambleDimensionAudio))
|
||||
{
|
||||
var audioType = AudioTypeHandler.GetAudioType(system.Config.GlobalMusic.finalEndTimesBrambleDimensionAudio, system.Mod);
|
||||
Delay.FireOnNextUpdate(() => Locator.GetGlobalMusicController()._finalEndTimesDarkBrambleSource.AssignAudioLibraryClip(audioType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
using NewHorizons.External.Configs;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using static TextTranslation;
|
||||
|
||||
namespace NewHorizons.Handlers
|
||||
{
|
||||
@ -48,23 +52,48 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
|
||||
// Get the translated text
|
||||
if (dictionary.TryGetValue(language, out var table))
|
||||
if (table.TryGetValue(text, out var translatedText))
|
||||
return translatedText;
|
||||
if (TryGetTranslatedText(dictionary, language, text, out var translatedText))
|
||||
{
|
||||
return translatedText;
|
||||
}
|
||||
|
||||
if (warn) NHLogger.LogVerbose($"Defaulting to english for {text}");
|
||||
if (warn)
|
||||
{
|
||||
NHLogger.LogVerbose($"Defaulting to english for {text}");
|
||||
}
|
||||
|
||||
// Try to default to English
|
||||
if (dictionary.TryGetValue(TextTranslation.Language.ENGLISH, out var englishTable))
|
||||
if (englishTable.TryGetValue(text, out var englishText))
|
||||
return englishText;
|
||||
if (TryGetTranslatedText(dictionary, Language.ENGLISH, text, out translatedText))
|
||||
{
|
||||
return translatedText;
|
||||
}
|
||||
|
||||
if (warn) NHLogger.LogVerbose($"Defaulting to key for {text}");
|
||||
if (warn)
|
||||
{
|
||||
NHLogger.LogVerbose($"Defaulting to key for {text}");
|
||||
}
|
||||
|
||||
// Default to the key
|
||||
return text;
|
||||
}
|
||||
|
||||
private static bool TryGetTranslatedText(Dictionary<Language, Dictionary<string, string>> dict, Language language, string text, out string translatedText)
|
||||
{
|
||||
if (dict.TryGetValue(language, out var table))
|
||||
{
|
||||
if (table.TryGetValue(text, out translatedText))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Try without whitespace if its missing
|
||||
else if (table.TryGetValue(text.TruncateWhitespaceAndToLower(), out translatedText))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
translatedText = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void RegisterTranslation(TextTranslation.Language language, TranslationConfig config)
|
||||
{
|
||||
if (config.ShipLogDictionary != null && config.ShipLogDictionary.Count > 0)
|
||||
@ -85,8 +114,11 @@ namespace NewHorizons.Handlers
|
||||
if (!_dialogueTranslationDictionary.ContainsKey(language)) _dialogueTranslationDictionary.Add(language, new Dictionary<string, string>());
|
||||
foreach (var originalKey in config.DialogueDictionary.Keys)
|
||||
{
|
||||
var key = originalKey.Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "");
|
||||
var value = config.DialogueDictionary[originalKey].Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "");
|
||||
// Fix new lines in dialogue translations, remove whitespace from keys else if the dialogue has weird whitespace and line breaks it gets really annoying
|
||||
// to write translation keys for (can't just copy paste out of xml, have to start adding \\n and \\r and stuff
|
||||
// If any of these issues become relevant to other dictionaries we can bring this code over, but for now why fix what isnt broke
|
||||
var key = originalKey.Replace("\\n", "\n").Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "").TruncateWhitespaceAndToLower();
|
||||
var value = config.DialogueDictionary[originalKey].Replace("\\n", "\n").Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "");
|
||||
|
||||
if (!_dialogueTranslationDictionary[language].ContainsKey(key)) _dialogueTranslationDictionary[language].Add(key, value);
|
||||
else _dialogueTranslationDictionary[language][key] = value;
|
||||
@ -121,29 +153,63 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
}
|
||||
|
||||
public static (string, string) FixKeyValue(string key, string value)
|
||||
{
|
||||
key = key.Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "");
|
||||
value = value.Replace("<", "<").Replace(">", ">").Replace("<![CDATA[", "").Replace("]]>", "");
|
||||
|
||||
return (key, value);
|
||||
}
|
||||
|
||||
public static void AddDialogue(string rawText, bool trimRawTextForKey = false, params string[] rawPreText)
|
||||
{
|
||||
var key = string.Join(string.Empty, rawPreText) + (trimRawTextForKey? rawText.Trim() : rawText);
|
||||
|
||||
var text = GetTranslation(rawText, TextType.DIALOGUE);
|
||||
var value = GetTranslation(rawText, TextType.DIALOGUE);
|
||||
|
||||
TextTranslation.Get().m_table.Insert(key, text);
|
||||
// Manually insert directly into the dictionary, otherwise it logs errors about duplicates but we want to allow replacing
|
||||
(key, value) = FixKeyValue(key, value);
|
||||
|
||||
TextTranslation.Get().m_table.theTable[key] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Two dialogue nodes might share indentical text but they will have different prefixes. Still, we want to reuse that old text.
|
||||
/// </summary>
|
||||
/// <param name="rawText"></param>
|
||||
/// <param name="oldPrefixes"></param>
|
||||
/// <param name="newPrefixes"></param>
|
||||
public static void ReuseDialogueTranslation(string rawText, string[] oldPrefixes, string[] newPrefixes)
|
||||
{
|
||||
var key = string.Join(string.Empty, newPrefixes) + rawText;
|
||||
var existingKey = string.Join(string.Empty, oldPrefixes) + rawText;
|
||||
if (TextTranslation.Get().m_table.theTable.TryGetValue(existingKey, out var existingTranslation))
|
||||
{
|
||||
TextTranslation.Get().m_table.theTable[key] = existingTranslation;
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogWarning($"Couldn't find translation key {existingKey}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddShipLog(string rawText, params string[] rawPreText)
|
||||
{
|
||||
var key = string.Join(string.Empty, rawPreText) + rawText;
|
||||
|
||||
string text = GetTranslation(rawText, TextType.SHIPLOG);
|
||||
string value = GetTranslation(rawText, TextType.SHIPLOG);
|
||||
|
||||
TextTranslation.Get().m_table.InsertShipLog(key, text);
|
||||
// Manually insert directly into the dictionary, otherwise it logs errors about duplicates but we want to allow replacing
|
||||
(key, value) = FixKeyValue(key, value);
|
||||
|
||||
TextTranslation.Get().m_table.theShipLogTable[key] = value;
|
||||
}
|
||||
|
||||
public static int AddUI(string rawText)
|
||||
{
|
||||
var uiTable = TextTranslation.Get().m_table.theUITable;
|
||||
|
||||
var text = GetTranslation(rawText, TextType.UI).ToUpper();
|
||||
var text = GetTranslation(rawText, TextType.UI).ToUpperFixed();
|
||||
|
||||
var key = uiTable.Keys.Max() + 1;
|
||||
try
|
||||
@ -154,7 +220,7 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
TextTranslation.Get().m_table.Insert_UI(key, text);
|
||||
TextTranslation.Get().m_table.theUITable[key] = text;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ namespace NewHorizons.Handlers
|
||||
{
|
||||
var vesselConfig = SystemDict[Instance.CurrentStarSystem].Config?.Vessel;
|
||||
var shouldSpawnOnVessel = IsVesselPresent() && (vesselConfig?.spawnOnVessel ?? false);
|
||||
return !Instance.IsWarpingFromShip && (Instance.IsWarpingFromVessel || shouldSpawnOnVessel);
|
||||
return !Instance.IsWarpingFromShip && (Instance.IsWarpingFromVessel || Instance.DidWarpFromVessel || shouldSpawnOnVessel);
|
||||
}
|
||||
|
||||
public static void LoadVessel()
|
||||
@ -56,18 +56,51 @@ namespace NewHorizons.Handlers
|
||||
if (IsVesselPresentAndActive())
|
||||
_vesselSpawnPoint = Instance.CurrentStarSystem == "SolarSystem" ? UpdateVessel() : CreateVessel();
|
||||
else
|
||||
_vesselSpawnPoint = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension").GetComponentInChildren<SpawnPoint>();
|
||||
{
|
||||
var vesselDimension = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension");
|
||||
var vesselDimensionSpawn = vesselDimension.GetComponentInChildren<SpawnPoint>(true);
|
||||
var vesselWarpController = vesselDimension.GetComponentInChildren<VesselWarpController>(true);
|
||||
|
||||
var defaultPlayerWarpPoint = new GameObject("DefaultPlayerWarpPos");
|
||||
defaultPlayerWarpPoint.transform.SetParent(vesselWarpController.transform, false);
|
||||
defaultPlayerWarpPoint.transform.localPosition = new Vector3(0, -5.82f, -6.56f);
|
||||
vesselWarpController._defaultPlayerWarpPoint = defaultPlayerWarpPoint.transform;
|
||||
|
||||
var vesselSpawnObj = new GameObject("SPAWN_Vessel");
|
||||
vesselSpawnObj.transform.SetParent(vesselWarpController.transform.parent.parent, false);
|
||||
vesselSpawnObj.transform.localPosition = new Vector3(-0.3f, -5.18f, -6.35f);
|
||||
var vesselSpawnPoint = vesselSpawnObj.AddComponent<VesselSpawnPoint>();
|
||||
vesselSpawnPoint.WarpController = vesselWarpController;
|
||||
vesselSpawnPoint._triggerVolumes = vesselDimensionSpawn._triggerVolumes;
|
||||
_vesselSpawnPoint = vesselSpawnPoint;
|
||||
}
|
||||
}
|
||||
|
||||
public static void TeleportToVessel()
|
||||
{
|
||||
var playerSpawner = Object.FindObjectOfType<PlayerSpawner>();
|
||||
NHLogger.LogVerbose("Debug warping into vessel");
|
||||
playerSpawner.DebugWarp(_vesselSpawnPoint);
|
||||
if (_vesselSpawnPoint is VesselSpawnPoint vesselSpawnPoint)
|
||||
{
|
||||
NHLogger.LogVerbose("Relative warping into vessel");
|
||||
vesselSpawnPoint.WarpPlayer();//Delay.FireOnNextUpdate(vesselSpawnPoint.WarpPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogVerbose("Debug warping into vessel");
|
||||
playerSpawner.DebugWarp(_vesselSpawnPoint);
|
||||
}
|
||||
Builder.General.SpawnPointBuilder.SuitUp();
|
||||
|
||||
LoadDB();
|
||||
}
|
||||
|
||||
public static void LoadDB()
|
||||
{
|
||||
if (Instance.CurrentStarSystem == "SolarSystem")
|
||||
{
|
||||
//Deactivate lock since we aren't in timber anymore
|
||||
GameObject.Destroy(SearchUtilities.Find("TimberHearth_Body/StreamingGroup_TH").GetComponent<StreamingLock>());
|
||||
|
||||
// Deactivate village music because for some reason it still plays.
|
||||
SearchUtilities.Find("TimberHearth_Body/Sector_TH/Sector_Village/Volumes_Village/MusicVolume_Village").GetComponent<VillageMusicVolume>().Deactivate();
|
||||
|
||||
@ -81,7 +114,7 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
}
|
||||
|
||||
public static EyeSpawnPoint CreateVessel()
|
||||
public static VesselSpawnPoint CreateVessel()
|
||||
{
|
||||
var system = SystemDict[Instance.CurrentStarSystem];
|
||||
|
||||
@ -131,16 +164,23 @@ namespace NewHorizons.Handlers
|
||||
vesselWarpController._targetWarpPlatform._whiteHole.OnCollapse += vesselWarpController._targetWarpPlatform.OnWhiteHoleCollapse;
|
||||
|
||||
GameObject blackHole = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension/Sector_VesselBridge/Interactibles_VesselBridge/BlackHole");
|
||||
GameObject newBlackHole = Object.Instantiate(blackHole, Vector3.zero, Quaternion.identity, singularityRoot.transform);
|
||||
GameObject newBlackHole = Object.Instantiate(blackHole, singularityRoot.transform);
|
||||
newBlackHole.transform.localPosition = Vector3.zero;
|
||||
newBlackHole.transform.localRotation = Quaternion.identity;
|
||||
newBlackHole.transform.localScale = Vector3.one;
|
||||
newBlackHole.name = "BlackHole";
|
||||
vesselWarpController._blackHole = newBlackHole.GetComponentInChildren<SingularityController>();
|
||||
vesselWarpController._blackHoleOneShot = vesselWarpController._blackHole.transform.parent.Find("BlackHoleAudio_OneShot").GetComponent<OWAudioSource>();
|
||||
|
||||
GameObject whiteHole = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension/Sector_VesselBridge/Interactibles_VesselBridge/WhiteHole");
|
||||
GameObject newWhiteHole = Object.Instantiate(whiteHole, Vector3.zero, Quaternion.identity, singularityRoot.transform);
|
||||
GameObject newWhiteHole = Object.Instantiate(whiteHole, singularityRoot.transform);
|
||||
newWhiteHole.transform.localPosition = Vector3.zero;
|
||||
newWhiteHole.transform.localRotation = Quaternion.identity;
|
||||
newWhiteHole.transform.localScale = Vector3.one;
|
||||
newWhiteHole.name = "WhiteHole";
|
||||
vesselWarpController._whiteHole = newWhiteHole.GetComponentInChildren<SingularityController>();
|
||||
vesselWarpController._whiteHoleOneShot = vesselWarpController._whiteHole.transform.parent.Find("WhiteHoleAudio_OneShot").GetComponent<OWAudioSource>();
|
||||
vesselWarpController._whiteHole._startActive = true;
|
||||
|
||||
vesselObject.GetComponent<MapMarker>()._labelID = (UITextType)TranslationHandler.AddUI("Vessel");
|
||||
|
||||
@ -165,6 +205,17 @@ namespace NewHorizons.Handlers
|
||||
Object.Destroy(rfVolume.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParentBody)
|
||||
{
|
||||
foreach (OWRigidbody dynamicProp in vesselObject.GetComponentsInChildren<OWRigidbody>(true))
|
||||
{
|
||||
if (dynamicProp.GetComponent<NomaiInterfaceOrb>() == null)
|
||||
{
|
||||
dynamicProp.gameObject.AddComponent<FixPhysics>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var attachWarpExitToVessel = system.Config.Vessel?.warpExit?.attachToVessel ?? false;
|
||||
var warpExitParent = vesselWarpController._targetWarpPlatform.transform.parent;
|
||||
@ -186,20 +237,22 @@ namespace NewHorizons.Handlers
|
||||
}
|
||||
}
|
||||
|
||||
EyeSpawnPoint eyeSpawnPoint = vesselObject.GetComponentInChildren<EyeSpawnPoint>(true);
|
||||
VesselSpawnPoint spawnPoint = vesselObject.GetComponentInChildren<VesselSpawnPoint>(true);
|
||||
if (ShouldSpawnAtVessel())
|
||||
{
|
||||
system.SpawnPoint = eyeSpawnPoint;
|
||||
system.SpawnPoint = spawnPoint;
|
||||
}
|
||||
|
||||
vesselObject.SetActive(true);
|
||||
|
||||
Delay.FireOnNextUpdate(() => SetupWarpController(vesselWarpController));
|
||||
var power = vesselWarpController.transform.Find("PowerSwitchInterface");
|
||||
var orb = power.GetComponentInChildren<NomaiInterfaceOrb>(true);
|
||||
Delay.FireOnNextUpdate(() => SetupWarpController(vesselWarpController, orb));
|
||||
|
||||
return eyeSpawnPoint;
|
||||
return spawnPoint;
|
||||
}
|
||||
|
||||
public static SpawnPoint UpdateVessel()
|
||||
public static VesselSpawnPoint UpdateVessel()
|
||||
{
|
||||
var system = SystemDict[Instance.CurrentStarSystem];
|
||||
|
||||
@ -207,7 +260,7 @@ namespace NewHorizons.Handlers
|
||||
var vectorSector = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension");
|
||||
VesselObject = vectorSector;
|
||||
|
||||
var spawnPoint = vectorSector.GetComponentInChildren<SpawnPoint>();
|
||||
var spawnPoint = vectorSector.GetComponentInChildren<SpawnPoint>(true);
|
||||
|
||||
VesselWarpController vesselWarpController = vectorSector.GetComponentInChildren<VesselWarpController>(true);
|
||||
WarpController = vesselWarpController;
|
||||
@ -219,12 +272,29 @@ namespace NewHorizons.Handlers
|
||||
vesselWarpController._whiteHoleOneShot = vesselWarpController._whiteHole.transform.parent.Find("WhiteHoleAudio_OneShot").GetComponent<OWAudioSource>();
|
||||
}
|
||||
|
||||
Delay.FireOnNextUpdate(() => SetupWarpController(vesselWarpController, true));
|
||||
vesselWarpController._whiteHole._startActive = true;
|
||||
vesselWarpController._whiteHole.Stabilize();
|
||||
|
||||
return spawnPoint;
|
||||
var defaultPlayerWarpPoint = new GameObject("DefaultPlayerWarpPos");
|
||||
defaultPlayerWarpPoint.transform.SetParent(vesselWarpController.transform, false);
|
||||
defaultPlayerWarpPoint.transform.localPosition = new Vector3(0, -5.82f, -6.56f);
|
||||
vesselWarpController._defaultPlayerWarpPoint = defaultPlayerWarpPoint.transform;
|
||||
|
||||
var vesselSpawnObj = new GameObject("SPAWN_Vessel");
|
||||
vesselSpawnObj.transform.SetParent(vesselWarpController.transform.parent.parent, false);
|
||||
vesselSpawnObj.transform.localPosition = new Vector3(-0.3f, -5.18f, -6.35f);
|
||||
var vesselSpawnPoint = vesselSpawnObj.AddComponent<VesselSpawnPoint>();
|
||||
vesselSpawnPoint.WarpController = vesselWarpController;
|
||||
vesselSpawnPoint._triggerVolumes = spawnPoint._triggerVolumes;
|
||||
|
||||
var power = vesselWarpController.transform.Find("PowerSwitchInterface");
|
||||
var orb = power.GetComponentInChildren<NomaiInterfaceOrb>(true);
|
||||
Delay.FireOnNextUpdate(() => SetupWarpController(vesselWarpController, orb, true));
|
||||
|
||||
return vesselSpawnPoint;
|
||||
}
|
||||
|
||||
public static void SetupWarpController(VesselWarpController vesselWarpController, bool db = false)
|
||||
public static void SetupWarpController(VesselWarpController vesselWarpController, NomaiInterfaceOrb orb, bool db = false)
|
||||
{
|
||||
if (db)
|
||||
{
|
||||
@ -259,17 +329,33 @@ namespace NewHorizons.Handlers
|
||||
if (light.GetLight()) light.GetLight().enabled = true;
|
||||
}
|
||||
}
|
||||
vesselWarpController._coreSocket.PlaceIntoSocket(newCore);
|
||||
vesselWarpController._coreSocket._socketedItem = newCore;
|
||||
newCore.SocketItem(vesselWarpController._coreSocket._socketTransform, vesselWarpController._coreSocket._sector);
|
||||
newCore.PlaySocketAnimation();
|
||||
vesselWarpController._coreSocket.enabled = true;
|
||||
vesselWarpController.SetPowered(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (NomaiLamp lamp in vesselWarpController.transform.root.GetComponentsInChildren<NomaiLamp>(true))
|
||||
{
|
||||
lamp._startOn = true;
|
||||
lamp.Awake();
|
||||
}
|
||||
}
|
||||
|
||||
vesselWarpController.OnSlotDeactivated(vesselWarpController._coordinatePowerSlot);
|
||||
if (!db) vesselWarpController.OnSlotActivated(vesselWarpController._coordinatePowerSlot);
|
||||
vesselWarpController._gravityVolume.SetFieldMagnitude(vesselWarpController._origGravityMagnitude);
|
||||
vesselWarpController._coreCable.SetPowered(true);
|
||||
vesselWarpController._coordinateCable.SetPowered(!db);
|
||||
vesselWarpController._warpPlatformCable.SetPowered(false);
|
||||
orb.SetOrbPosition(vesselWarpController._coordinatePowerSlot.transform.position);
|
||||
orb._occupiedSlot = vesselWarpController._coordinatePowerSlot;
|
||||
orb._enterSlotTime = Time.time;
|
||||
Delay.RunWhen(() => !vesselWarpController._coordinateInterface._pillarRaised, () => vesselWarpController.OnSlotActivated(vesselWarpController._coordinatePowerSlot));
|
||||
vesselWarpController._coordinateCable.SetPowered(true);
|
||||
vesselWarpController._cageClosed = true;
|
||||
if (vesselWarpController._cageAnimator != null)
|
||||
{
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using NewHorizons.Handlers;
|
||||
using OWML.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -207,5 +206,13 @@ namespace NewHorizons
|
||||
/// <returns></returns>
|
||||
string GetTranslationForOtherText(string text);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Registers a subtitle for the main menu.
|
||||
/// Call this once before the main menu finishes loading
|
||||
/// </summary>
|
||||
/// <param name="mod"></param>
|
||||
/// <param name="filePath"></param>
|
||||
void AddSubtitle(IModBehaviour mod, string filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,19 +46,21 @@ namespace NewHorizons
|
||||
// Settings
|
||||
public static bool Debug { get; private set; }
|
||||
public static bool VerboseLogs { get; private set; }
|
||||
private static bool _useCustomTitleScreen;
|
||||
public static bool SequentialPreCaching { get; private set; }
|
||||
public static bool CustomTitleScreen { get; private set; }
|
||||
public static string DefaultSystemOverride { get; private set; }
|
||||
private static bool _wasConfigured = false;
|
||||
private static string _defaultSystemOverride;
|
||||
|
||||
public static Dictionary<string, NewHorizonsSystem> SystemDict = new Dictionary<string, NewHorizonsSystem>();
|
||||
public static Dictionary<string, List<NewHorizonsBody>> BodyDict = new Dictionary<string, List<NewHorizonsBody>>();
|
||||
public static List<IModBehaviour> MountedAddons = new List<IModBehaviour>();
|
||||
public static Dictionary<string, NewHorizonsSystem> SystemDict = new();
|
||||
public static Dictionary<string, List<NewHorizonsBody>> BodyDict = new();
|
||||
public static List<IModBehaviour> MountedAddons = new();
|
||||
public static Dictionary<IModBehaviour, AddonConfig> AddonConfigs = new();
|
||||
|
||||
public static float SecondsElapsedInLoop = -1;
|
||||
|
||||
public static bool IsSystemReady { get; private set; }
|
||||
|
||||
public string DefaultStarSystem => SystemDict.ContainsKey(_defaultSystemOverride) ? _defaultSystemOverride : _defaultStarSystem;
|
||||
public string DefaultStarSystem => SystemDict.ContainsKey(DefaultSystemOverride) ? DefaultSystemOverride : _defaultStarSystem;
|
||||
public string CurrentStarSystem
|
||||
{
|
||||
get
|
||||
@ -109,7 +111,12 @@ namespace NewHorizons
|
||||
public StarSystemEvent OnStarSystemLoaded = new();
|
||||
public StarSystemEvent OnPlanetLoaded = new();
|
||||
|
||||
public static bool HasDLC { get => EntitlementsManager.IsDlcOwned() == EntitlementsManager.AsyncOwnershipStatus.Owned; }
|
||||
/// <summary>
|
||||
/// Depending on platform, the AsyncOwnershipStatus might not be ready by the time we go to check it.
|
||||
/// If that happens, I guess we just have to assume they do own the DLC.
|
||||
/// Better to false positive than false negative and annoy people every time they launch the game when they do own the DLC
|
||||
/// </summary>
|
||||
public static bool HasDLC { get => EntitlementsManager.IsDlcOwned() != EntitlementsManager.AsyncOwnershipStatus.NotOwned; }
|
||||
|
||||
public static StarSystemConfig GetCurrentSystemConfig => SystemDict[Instance.CurrentStarSystem].Config;
|
||||
|
||||
@ -124,8 +131,9 @@ namespace NewHorizons
|
||||
|
||||
var currentScene = SceneManager.GetActiveScene().name;
|
||||
|
||||
Debug = config.GetSettingsValue<bool>("Debug");
|
||||
VerboseLogs = config.GetSettingsValue<bool>("Verbose Logs");
|
||||
Debug = config.GetSettingsValue<bool>(nameof(Debug));
|
||||
VerboseLogs = config.GetSettingsValue<bool>(nameof(VerboseLogs));
|
||||
SequentialPreCaching = config.GetSettingsValue<bool>(nameof(SequentialPreCaching));
|
||||
|
||||
if (currentScene == "SolarSystem")
|
||||
{
|
||||
@ -137,19 +145,19 @@ namespace NewHorizons
|
||||
else if (Debug) NHLogger.UpdateLogLevel(NHLogger.LogType.Log);
|
||||
else NHLogger.UpdateLogLevel(NHLogger.LogType.Error);
|
||||
|
||||
var oldDefaultSystemOverride = _defaultSystemOverride;
|
||||
_defaultSystemOverride = config.GetSettingsValue<string>("Default System Override");
|
||||
if (oldDefaultSystemOverride != _defaultSystemOverride)
|
||||
var oldDefaultSystemOverride = DefaultSystemOverride;
|
||||
DefaultSystemOverride = config.GetSettingsValue<string>(nameof(DefaultSystemOverride));
|
||||
if (oldDefaultSystemOverride != DefaultSystemOverride)
|
||||
{
|
||||
ResetCurrentStarSystem();
|
||||
NHLogger.Log($"Changed default star system override to {_defaultSystemOverride}");
|
||||
NHLogger.Log($"Changed default star system override to {DefaultSystemOverride}");
|
||||
}
|
||||
|
||||
var wasUsingCustomTitleScreen = _useCustomTitleScreen;
|
||||
_useCustomTitleScreen = config.GetSettingsValue<bool>("Custom title screen");
|
||||
var wasUsingCustomTitleScreen = CustomTitleScreen;
|
||||
CustomTitleScreen = config.GetSettingsValue<bool>(nameof(CustomTitleScreen));
|
||||
// Reload the title screen if this was updated on it
|
||||
// Don't reload if we haven't configured yet (called on game start)
|
||||
if (wasUsingCustomTitleScreen != _useCustomTitleScreen && SceneManager.GetActiveScene().name == "TitleScreen" && _wasConfigured)
|
||||
if (wasUsingCustomTitleScreen != CustomTitleScreen && SceneManager.GetActiveScene().name == "TitleScreen" && _wasConfigured)
|
||||
{
|
||||
NHLogger.LogVerbose("Reloading");
|
||||
SceneManager.LoadScene("TitleScreen", LoadSceneMode.Single);
|
||||
@ -186,7 +194,7 @@ namespace NewHorizons
|
||||
Config =
|
||||
{
|
||||
destroyStockPlanets = false,
|
||||
factRequiredForWarp = "OPC_EYE_COORDINATES_X1",
|
||||
//factRequiredForWarp = "OPC_EYE_COORDINATES_X1",
|
||||
Vessel = new StarSystemConfig.VesselModule()
|
||||
{
|
||||
coords = new StarSystemConfig.NomaiCoordinates
|
||||
@ -195,7 +203,8 @@ namespace NewHorizons
|
||||
y = new int[4] { 3, 0, 1, 4 },
|
||||
z = new int[6] { 1, 2, 3, 0, 5, 4 }
|
||||
}
|
||||
}
|
||||
},
|
||||
canEnterViaWarpDrive = false
|
||||
}
|
||||
};
|
||||
|
||||
@ -220,6 +229,13 @@ namespace NewHorizons
|
||||
// the campfire on the title screen calls this from RegisterShape before it gets patched, so we have to call it again. lol
|
||||
ShapeManager.Initialize();
|
||||
|
||||
// Fix a thing (thanks jeff mobius) 1.1.15 updated the game over fonts to only include the characters they needed
|
||||
for (int i = 0; i < TextTranslation.s_theTable.m_gameOverFonts.Length; i++)
|
||||
{
|
||||
var existingFont = TextTranslation.s_theTable.m_dynamicFonts[i];
|
||||
TextTranslation.s_theTable.m_gameOverFonts[i] = existingFont;
|
||||
}
|
||||
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
SceneManager.sceneUnloaded += OnSceneUnloaded;
|
||||
|
||||
@ -256,7 +272,6 @@ namespace NewHorizons
|
||||
// Call this from the menu since we hadn't hooked onto the event yet
|
||||
Delay.FireOnNextUpdate(() => OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single));
|
||||
Delay.FireOnNextUpdate(() => _firstLoad = false);
|
||||
Instance.ModHelper.Menus.PauseMenu.OnInit += DebugReload.InitializePauseMenu;
|
||||
|
||||
MenuHandler.Init();
|
||||
AchievementHandler.Init();
|
||||
@ -268,6 +283,13 @@ namespace NewHorizons
|
||||
LoadAddonManifest("Assets/addon-manifest.json", this);
|
||||
}
|
||||
|
||||
public override void SetupPauseMenu(IPauseMenuManager pauseMenu)
|
||||
{
|
||||
base.SetupPauseMenu(pauseMenu);
|
||||
DebugReload.InitializePauseMenu(pauseMenu);
|
||||
DebugMenu.InitializePauseMenu(pauseMenu);
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
NHLogger.Log($"Destroying NewHorizons");
|
||||
@ -321,6 +343,8 @@ namespace NewHorizons
|
||||
{
|
||||
try
|
||||
{
|
||||
EyeDetailCacher.Init();
|
||||
|
||||
AtmosphereBuilder.InitPrefabs();
|
||||
BrambleDimensionBuilder.InitPrefabs();
|
||||
BrambleNodeBuilder.InitPrefabs();
|
||||
@ -374,9 +398,11 @@ namespace NewHorizons
|
||||
else if (IsWarpingBackToEye)
|
||||
{
|
||||
IsWarpingBackToEye = false;
|
||||
OWTime.Pause(OWTime.PauseType.Loading);
|
||||
LoadManager.LoadSceneImmediate(OWScene.EyeOfTheUniverse);
|
||||
OWTime.Unpause(OWTime.PauseType.Loading);
|
||||
ManualOnStartSceneLoad(OWScene.EyeOfTheUniverse);
|
||||
// LoadSceneImmediate doesn't cover the screen and you see the solar system for a frame without this
|
||||
LoadManager.s_instance._fadeCanvas.enabled = true;
|
||||
LoadManager.s_instance._fadeImage.color = Color.black;
|
||||
LoadManager.LoadSceneImmediate(OWScene.EyeOfTheUniverse);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -404,7 +430,7 @@ namespace NewHorizons
|
||||
|
||||
IsChangingStarSystem = false;
|
||||
|
||||
if (isTitleScreen && _useCustomTitleScreen)
|
||||
if (isTitleScreen && CustomTitleScreen)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -505,10 +531,14 @@ namespace NewHorizons
|
||||
|
||||
// We are in a custom system on the first loop -> The time loop isn't active, that's not very good
|
||||
// TimeLoop uses the launch codes condition to know if the loop is active or not
|
||||
// We also skip them to loop 2, else if they enter a credits volume in this loop they get reset
|
||||
if (CurrentStarSystem != "SolarSystem" && PlayerData.LoadLoopCount() == 1)
|
||||
{
|
||||
PlayerData.SaveLoopCount(2);
|
||||
PlayerData.SetPersistentCondition("LAUNCH_CODES_GIVEN", true);
|
||||
}
|
||||
|
||||
if (shouldWarpInFromVessel) VesselWarpHandler.LoadDB();
|
||||
}
|
||||
else if (isEyeOfTheUniverse)
|
||||
{
|
||||
@ -588,6 +618,7 @@ namespace NewHorizons
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugRaycaster>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugPropPlacer>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugMenu>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<PlayerShipAtmosphereDetectorFix>();
|
||||
|
||||
PlayerSpawnHandler.OnSystemReady(shouldWarpInFromShip, shouldWarpInFromVessel);
|
||||
|
||||
@ -611,6 +642,39 @@ namespace NewHorizons
|
||||
HasWarpDrive = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sometimes we call LoadSceneImmediate, which doesnt do the required event firing for mods to be happy.
|
||||
/// this method emulates that via copying parts of LoadManager.
|
||||
/// </summary>
|
||||
public static void ManualOnStartSceneLoad(OWScene scene)
|
||||
{
|
||||
LoadManager.s_loadSceneJob = new LoadManager.LoadSceneJob();
|
||||
LoadManager.s_loadSceneJob.sceneToLoad = scene;
|
||||
LoadManager.s_loadSceneJob.fadeType = LoadManager.FadeType.None;
|
||||
LoadManager.s_loadSceneJob.fadeLength = 0;
|
||||
LoadManager.s_loadSceneJob.pauseDuringFade = true;
|
||||
LoadManager.s_loadSceneJob.asyncOperation = false;
|
||||
LoadManager.s_loadSceneJob.skipPreLoadMemoryDump = false;
|
||||
LoadManager.s_loadSceneJob.skipVsyncChange = false;
|
||||
|
||||
LoadManager.s_loadingScene = LoadManager.s_loadSceneJob.sceneToLoad;
|
||||
LoadManager.s_fadeType = LoadManager.s_loadSceneJob.fadeType;
|
||||
LoadManager.s_fadeStartTime = Time.unscaledTime;
|
||||
LoadManager.s_fadeLength = LoadManager.s_loadSceneJob.fadeLength;
|
||||
LoadManager.s_pauseDuringFade = LoadManager.s_loadSceneJob.pauseDuringFade;
|
||||
LoadManager.s_skipVsyncChange = LoadManager.s_loadSceneJob.skipVsyncChange;
|
||||
|
||||
// cant fire events from outside of class without reflection
|
||||
((Delegate)AccessTools.Field(typeof(LoadManager), nameof(LoadManager.OnStartSceneLoad)).GetValue(null))
|
||||
.DynamicInvoke(LoadManager.s_currentScene, LoadManager.s_loadingScene);
|
||||
|
||||
if (LoadManager.s_pauseDuringFade)
|
||||
{
|
||||
OWTime.Pause(OWTime.PauseType.Loading);
|
||||
}
|
||||
|
||||
LoadManager.s_loadSceneJob = null;
|
||||
}
|
||||
|
||||
#region Load
|
||||
public void LoadStarSystemConfig(string starSystemName, StarSystemConfig starSystemConfig, string relativePath, IModBehaviour mod)
|
||||
@ -630,8 +694,25 @@ namespace NewHorizons
|
||||
|
||||
if (SystemDict.ContainsKey(starSystemName))
|
||||
{
|
||||
if (string.IsNullOrEmpty(SystemDict[starSystemName].Config.travelAudio) && SystemDict[starSystemName].Config.Skybox == null)
|
||||
// Both changing the Mod and RelativePath are weird and will likely cause incompat issues if two mods both affected the same system
|
||||
// It's mostly just to fix up the config compared to the default one NH makes for the base StarSystem
|
||||
|
||||
if (SystemDict[starSystemName].Config.GlobalMusic == null && SystemDict[starSystemName].Config.Skybox == null)
|
||||
{
|
||||
SystemDict[starSystemName].Mod = mod;
|
||||
}
|
||||
|
||||
// If a mod contains a change to the default system, set the relative path.
|
||||
// Warning: If multiple systems make changes to the default system, only the relativePath will be set to the last mod loaded.
|
||||
if (string.IsNullOrEmpty(SystemDict[starSystemName].RelativePath))
|
||||
{
|
||||
SystemDict[starSystemName].RelativePath = relativePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
NHLogger.LogWarning($"Two (or more) mods are making system changes to {starSystemName} which may result in errors");
|
||||
}
|
||||
|
||||
SystemDict[starSystemName].Config.Merge(starSystemConfig);
|
||||
}
|
||||
else
|
||||
@ -734,6 +815,12 @@ namespace NewHorizons
|
||||
|
||||
var addonConfig = mod.ModHelper.Storage.Load<AddonConfig>(file, false);
|
||||
|
||||
if (addonConfig == null)
|
||||
{
|
||||
NHLogger.LogError($"Addon manifest for {mod.ModHelper.Manifest.Name} could not load, check your JSON");
|
||||
return;
|
||||
}
|
||||
|
||||
if (addonConfig.achievements != null)
|
||||
{
|
||||
AchievementHandler.RegisterAddon(addonConfig, mod as ModBehaviour);
|
||||
@ -747,6 +834,15 @@ namespace NewHorizons
|
||||
{
|
||||
MenuHandler.RegisterOneTimePopup(mod, TranslationHandler.GetTranslation(addonConfig.popupMessage, TranslationHandler.TextType.UI), addonConfig.repeatPopup);
|
||||
}
|
||||
if (addonConfig.preloadAssetBundles != null)
|
||||
{
|
||||
foreach (var bundle in addonConfig.preloadAssetBundles)
|
||||
{
|
||||
AssetBundleUtilities.PreloadBundle(bundle, mod);
|
||||
}
|
||||
}
|
||||
|
||||
AddonConfigs[mod] = addonConfig;
|
||||
}
|
||||
|
||||
private void LoadTranslations(string folder, IModBehaviour mod)
|
||||
@ -756,7 +852,7 @@ namespace NewHorizons
|
||||
{
|
||||
if (language is TextTranslation.Language.UNKNOWN or TextTranslation.Language.TOTAL) continue;
|
||||
|
||||
var relativeFile = Path.Combine("translations", language.ToString().ToLower() + ".json");
|
||||
var relativeFile = Path.Combine("translations", language.ToString().ToLowerInvariant() + ".json");
|
||||
|
||||
if (File.Exists(Path.Combine(folder, relativeFile)))
|
||||
{
|
||||
@ -839,6 +935,10 @@ namespace NewHorizons
|
||||
{
|
||||
_defaultStarSystem = defaultSystem;
|
||||
}
|
||||
if (LoadManager.GetCurrentScene() != OWScene.SolarSystem && LoadManager.GetCurrentScene() != OWScene.EyeOfTheUniverse)
|
||||
{
|
||||
CurrentStarSystem = _defaultStarSystem;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Load
|
||||
@ -876,6 +976,7 @@ namespace NewHorizons
|
||||
IsWarpingFromVessel = vessel;
|
||||
DidWarpFromVessel = false;
|
||||
OnChangeStarSystem?.Invoke(newStarSystem);
|
||||
VesselWarpController.s_relativeLocationSaved = false;
|
||||
|
||||
NHLogger.Log($"Warping to {newStarSystem}");
|
||||
if (warp && ShipWarpController) ShipWarpController.WarpOut();
|
||||
@ -891,7 +992,8 @@ namespace NewHorizons
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerData.SaveEyeCompletion(); // So that the title screen doesn't keep warping you back to eye
|
||||
if (!IsWarpingBackToEye)
|
||||
PlayerData.SaveEyeCompletion(); // So that the title screen doesn't keep warping you back to eye
|
||||
|
||||
if (SystemDict[CurrentStarSystem].Config.enableTimeLoop) SecondsElapsedInLoop = TimeLoop.GetSecondsElapsed();
|
||||
else SecondsElapsedInLoop = -1;
|
||||
@ -909,13 +1011,44 @@ namespace NewHorizons
|
||||
{
|
||||
// Slide reel unloading is tied to being removed from the sector, so we do that here to prevent a softlock
|
||||
Locator.GetPlayerSectorDetector().RemoveFromAllSectors();
|
||||
ManualOnStartSceneLoad(sceneToLoad); // putting it before fade breaks ship warp effect cuz pause
|
||||
LoadManager.LoadSceneImmediate(sceneToLoad);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exclusively for <see cref="Patches.WarpPatches.VesselWarpControllerPatches.VesselWarpController_OnSlotActivated(VesselWarpController, NomaiInterfaceSlot)"/>
|
||||
/// </summary>
|
||||
internal void ChangeCurrentStarSystemVesselAsync(string newStarSystem)
|
||||
{
|
||||
if (IsChangingStarSystem) return;
|
||||
|
||||
if (LoadManager.GetCurrentScene() == OWScene.SolarSystem || LoadManager.GetCurrentScene() == OWScene.EyeOfTheUniverse)
|
||||
{
|
||||
IsWarpingFromShip = false;
|
||||
IsWarpingFromVessel = true;
|
||||
DidWarpFromVessel = false;
|
||||
OnChangeStarSystem?.Invoke(newStarSystem);
|
||||
|
||||
NHLogger.Log($"Vessel warping to {newStarSystem}");
|
||||
IsChangingStarSystem = true;
|
||||
WearingSuit = PlayerState.IsWearingSuit();
|
||||
|
||||
PlayerData.SaveEyeCompletion(); // So that the title screen doesn't keep warping you back to eye
|
||||
|
||||
if (SystemDict[CurrentStarSystem].Config.enableTimeLoop) SecondsElapsedInLoop = TimeLoop.GetSecondsElapsed();
|
||||
else SecondsElapsedInLoop = -1;
|
||||
|
||||
CurrentStarSystem = newStarSystem;
|
||||
|
||||
LoadManager.LoadSceneAsync(OWScene.SolarSystem, false, LoadManager.FadeType.ToBlack);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDeath(DeathType _)
|
||||
{
|
||||
VesselWarpController.s_relativeLocationSaved = false;
|
||||
// We reset the solar system on death
|
||||
if (!IsChangingStarSystem)
|
||||
{
|
||||
@ -927,13 +1060,17 @@ namespace NewHorizons
|
||||
|
||||
private void ResetCurrentStarSystem()
|
||||
{
|
||||
if (SystemDict.ContainsKey(_defaultSystemOverride))
|
||||
if (SystemDict.ContainsKey(DefaultSystemOverride))
|
||||
{
|
||||
CurrentStarSystem = _defaultSystemOverride;
|
||||
CurrentStarSystem = DefaultSystemOverride;
|
||||
|
||||
if (BodyDict.TryGetValue(_defaultSystemOverride, out var bodies) && bodies.Any(x => x.Config?.Spawn?.shipSpawn != null))
|
||||
// #738 - Sometimes the override will not support spawning regularly, so always warp in if possible
|
||||
if (SystemDict[DefaultSystemOverride].Config.Vessel?.spawnOnVessel == true)
|
||||
{
|
||||
IsWarpingFromVessel = true;
|
||||
}
|
||||
else if (BodyDict.TryGetValue(DefaultSystemOverride, out var bodies) && bodies.Any(x => x.Config?.Spawn?.shipSpawn != null))
|
||||
{
|
||||
// #738 - Sometimes the override will not support spawning regularly, so always warp in if possible
|
||||
IsWarpingFromShip = true;
|
||||
}
|
||||
else
|
||||
@ -944,9 +1081,9 @@ namespace NewHorizons
|
||||
else
|
||||
{
|
||||
// Ignore first load because it doesn't even know what systems we have
|
||||
if (!_firstLoad && !string.IsNullOrEmpty(_defaultSystemOverride))
|
||||
if (!_firstLoad && !string.IsNullOrEmpty(DefaultSystemOverride))
|
||||
{
|
||||
NHLogger.LogError($"The given default system override {_defaultSystemOverride} is invalid - no system exists with that name");
|
||||
NHLogger.LogError($"The given default system override {DefaultSystemOverride} is invalid - no system exists with that name");
|
||||
}
|
||||
|
||||
CurrentStarSystem = _defaultStarSystem;
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
<DebugType>none</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.14.768" />
|
||||
<PackageReference Include="OWML" Version="2.9.8" />
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.15.1018" />
|
||||
<PackageReference Include="OWML" Version="2.12.1" />
|
||||
<Reference Include="../Lib/System.ComponentModel.Annotations.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -28,7 +28,6 @@ using static NewHorizons.External.Modules.ShipLogModule;
|
||||
|
||||
namespace NewHorizons
|
||||
{
|
||||
|
||||
public class NewHorizonsApi : INewHorizons
|
||||
{
|
||||
[Obsolete("Create(Dictionary<string, object> config) is deprecated, please use LoadConfigs(IModBehaviour mod) instead")]
|
||||
@ -144,9 +143,11 @@ namespace NewHorizons
|
||||
public object QueryBody(Type outType, string bodyName, string jsonPath)
|
||||
{
|
||||
var planet = Main.BodyDict[Main.Instance.CurrentStarSystem].Find((b) => b.Config.name == bodyName);
|
||||
return planet == null
|
||||
? null
|
||||
: QueryJson(outType, Path.Combine(planet.Mod.ModHelper.Manifest.ModFolderPath, planet.RelativePath), jsonPath);
|
||||
if (planet == null){
|
||||
NHLogger.LogError($"Could not find planet with body name {bodyName}.");
|
||||
return null;
|
||||
}
|
||||
return QueryJson(outType, Path.Combine(planet.Mod.ModHelper.Manifest.ModFolderPath, planet.RelativePath), jsonPath);
|
||||
}
|
||||
|
||||
public T QueryBody<T>(string bodyName, string jsonPath)
|
||||
@ -337,5 +338,7 @@ namespace NewHorizons
|
||||
public string GetTranslationForUI(string text) => TranslationHandler.GetTranslation(text, TranslationHandler.TextType.UI);
|
||||
|
||||
public string GetTranslationForOtherText(string text) => TranslationHandler.GetTranslation(text, TranslationHandler.TextType.OTHER);
|
||||
|
||||
public void AddSubtitle(IModBehaviour mod, string filePath) => SubtitlesHandler.RegisterAdditionalSubtitle(mod, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NewHorizons.OtherMods.MenuFramework
|
||||
{
|
||||
public interface IMenuAPI
|
||||
{
|
||||
GameObject TitleScreen_MakeMenuOpenButton(string name, int index, Menu menuToOpen);
|
||||
GameObject TitleScreen_MakeSceneLoadButton(string name, int index, SubmitActionLoadScene.LoadableScenes sceneToLoad, PopupMenu confirmPopup = null);
|
||||
Button TitleScreen_MakeSimpleButton(string name, int index);
|
||||
GameObject PauseMenu_MakeMenuOpenButton(string name, Menu menuToOpen, Menu customMenu = null);
|
||||
GameObject PauseMenu_MakeSceneLoadButton(string name, SubmitActionLoadScene.LoadableScenes sceneToLoad, PopupMenu confirmPopup = null, Menu customMenu = null);
|
||||
Button PauseMenu_MakeSimpleButton(string name, Menu customMenu = null);
|
||||
Menu PauseMenu_MakePauseListMenu(string title);
|
||||
PopupMenu MakeTwoChoicePopup(string message, string confirmText, string cancelText);
|
||||
PopupInputMenu MakeInputFieldPopup(string message, string placeholderMessage, string confirmText, string cancelText);
|
||||
PopupMenu MakeInfoPopup(string message, string continueButtonText);
|
||||
void RegisterStartupPopup(string message);
|
||||
}
|
||||
}
|
||||
@ -11,15 +11,11 @@ namespace NewHorizons.OtherMods.MenuFramework
|
||||
{
|
||||
public static class MenuHandler
|
||||
{
|
||||
private static IMenuAPI _menuApi;
|
||||
|
||||
private static List<(IModBehaviour mod, string message, bool repeat)> _registeredPopups = new();
|
||||
private static List<string> _failedFiles = new();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_menuApi = Main.Instance.ModHelper.Interaction.TryGetModApi<IMenuAPI>("_nebula.MenuFramework");
|
||||
|
||||
TextTranslation.Get().OnLanguageChanged += OnLanguageChanged;
|
||||
}
|
||||
|
||||
@ -35,14 +31,14 @@ namespace NewHorizons.OtherMods.MenuFramework
|
||||
Application.version);
|
||||
|
||||
NHLogger.LogError(warning);
|
||||
_menuApi.RegisterStartupPopup(warning);
|
||||
Main.Instance.ModHelper.MenuHelper.PopupMenuManager.RegisterStartupPopup(warning);
|
||||
}
|
||||
|
||||
foreach(var (mod, message, repeat) in _registeredPopups)
|
||||
{
|
||||
if (repeat || !NewHorizonsData.HasReadOneTimePopup(mod.ModHelper.Manifest.UniqueName))
|
||||
{
|
||||
_menuApi.RegisterStartupPopup(TranslationHandler.GetTranslation(message, TranslationHandler.TextType.UI));
|
||||
Main.Instance.ModHelper.MenuHelper.PopupMenuManager.RegisterStartupPopup(TranslationHandler.GetTranslation(message, TranslationHandler.TextType.UI));
|
||||
NewHorizonsData.ReadOneTimePopup(mod.ModHelper.Manifest.UniqueName);
|
||||
}
|
||||
}
|
||||
@ -52,7 +48,7 @@ namespace NewHorizons.OtherMods.MenuFramework
|
||||
var message = TranslationHandler.GetTranslation("JSON_FAILED_TO_LOAD", TranslationHandler.TextType.UI);
|
||||
var mods = string.Join(",", _failedFiles.Take(10));
|
||||
if (_failedFiles.Count > 10) mods += "...";
|
||||
_menuApi.RegisterStartupPopup(string.Format(message, mods));
|
||||
Main.Instance.ModHelper.MenuHelper.PopupMenuManager.RegisterStartupPopup(string.Format(message, mods));
|
||||
}
|
||||
|
||||
_registeredPopups.Clear();
|
||||
|
||||
26
NewHorizons/Patches/BrambleProjectionFixPatches.cs
Normal file
26
NewHorizons/Patches/BrambleProjectionFixPatches.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace NewHorizons.Patches;
|
||||
|
||||
/// <summary>
|
||||
/// Bug fix from the Outsider
|
||||
/// </summary>
|
||||
[HarmonyPatch]
|
||||
internal class BrambleProjectionFixPatches
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(FogWarpVolume), nameof(FogWarpVolume.WarpDetector))]
|
||||
public static bool FogWarpVolume_WarpDetector()
|
||||
{
|
||||
// Do not warp the player if they have entered the fog via a projection
|
||||
return !PlayerState.UsingNomaiRemoteCamera();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(FogWarpDetector), nameof(FogWarpDetector.FixedUpdate))]
|
||||
public static bool FogWarpDetector_FixedUpdate()
|
||||
{
|
||||
// Do not warp the player if they have entered the fog via a projection
|
||||
return !PlayerState.UsingNomaiRemoteCamera();
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,10 @@ public static class CharacterDialogueTreePatches
|
||||
|
||||
private static void OnAttachPlayerToPoint(this CharacterDialogueTree characterDialogueTree, OWRigidbody rigidbody)
|
||||
{
|
||||
characterDialogueTree.EndConversation();
|
||||
if (characterDialogueTree.InConversation())
|
||||
{
|
||||
characterDialogueTree.EndConversation();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
using HarmonyLib;
|
||||
using System.Collections;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace NewHorizons.Patches.DialoguePatches
|
||||
{
|
||||
@ -7,6 +9,29 @@ namespace NewHorizons.Patches.DialoguePatches
|
||||
{
|
||||
private static bool _wasLastDialogueInactive = false;
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(RemoteDialogueTrigger.Awake))]
|
||||
public static void RemoteDialogueTrigger_Awake(RemoteDialogueTrigger __instance)
|
||||
{
|
||||
// Wait for player to be up and moving before allowing them to trigger remote dialogue
|
||||
// Stops you getting locked into dialogue while waking up
|
||||
if (OWInput.GetInputMode() != InputMode.Character)
|
||||
{
|
||||
__instance._collider.enabled = false;
|
||||
__instance.StartCoroutine(AwakeCoroutine(__instance));
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerator AwakeCoroutine(RemoteDialogueTrigger instance)
|
||||
{
|
||||
while (OWInput.GetInputMode() != InputMode.Character)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
instance._collider.enabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should fix a bug where disabled a CharacterDialogueTree makes its related RemoteDialogueTriggers softlock your game
|
||||
/// </summary>
|
||||
|
||||
@ -63,7 +63,8 @@ namespace NewHorizons.Patches.EchoesOfTheEyePatches
|
||||
if (__instance._playerInEffectsRange)
|
||||
{
|
||||
// All this to change what fluidVolume we use on this line
|
||||
float num = __instance._fluidDetector.InFluidType(FluidVolume.Type.WATER) ? __instance._fluidDetector._alignmentFluid.GetFractionSubmerged(__instance._fluidDetector) : 0f;
|
||||
FluidVolume volume = __instance._fluidDetector._alignmentFluid;
|
||||
float num = __instance._fluidDetector.InFluidType(FluidVolume.Type.WATER) && volume != null ? volume.GetFractionSubmerged(__instance._fluidDetector) : 0f;
|
||||
bool allowMovement = num > 0.25f && num < 1f;
|
||||
__instance._effectsController.UpdateMovementAudio(allowMovement, __instance._lightSensors);
|
||||
__instance._effectsController.UpdateGroundedAudio(__instance._fluidDetector);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user