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 only-show-relevant-frequencies
This commit is contained in:
commit
4dfc8fa109
22
.github/workflows/release_build.yml
vendored
22
.github/workflows/release_build.yml
vendored
@ -22,13 +22,27 @@ on:
|
||||
- ".gitignore"
|
||||
|
||||
jobs:
|
||||
Check_Version:
|
||||
name: Check Version
|
||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'update-pr') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: "actions/checkout@v3"
|
||||
- name: Read Manifest
|
||||
id: read-manifest
|
||||
run: echo "manifest=$(< ./NewHorizons/manifest.json sed ':a;N;$!ba;s/\n/ /g')" >> $GITHUB_OUTPUT
|
||||
- name: Error
|
||||
if: ${{ steps.read-manifest.outputs.version != github.event.pull_request.title }}
|
||||
run: echo "::error file=manifest.json,title=Version Error::Hey DUMB-DUMB UPDATE THE MANIFEST VERSION" && exit 1
|
||||
Build:
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'update-pr') }}
|
||||
needs: Check_Version
|
||||
if: ${{ needs.Check_Version.result == 'success' && (github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'update-pr')) }}
|
||||
uses: ./.github/workflows/build.yaml
|
||||
with:
|
||||
build_type: Release
|
||||
Update_Schemas:
|
||||
name: 'Update Schemas'
|
||||
name: "Update Schemas"
|
||||
needs: Build
|
||||
if: ${{ needs.Build.outputs.schemas_changed == 'true' && github.ref == 'refs/heads/main' }} # Debug build will update schemas on push, so don't run if we're on pull request
|
||||
uses: ./.github/workflows/update_schemas.yml
|
||||
@ -36,7 +50,7 @@ jobs:
|
||||
artifact_name: NewHorizons-Schemas-Release
|
||||
secrets: inherit
|
||||
Update_Release:
|
||||
name: 'Create/Update Release Asset'
|
||||
name: "Create/Update Release Asset"
|
||||
needs: Build
|
||||
if: ${{ github.ref != 'refs/heads/main' && contains(github.event.pull_request.labels.*.name, 'update-pr') }}
|
||||
runs-on: ubuntu-latest
|
||||
@ -65,5 +79,3 @@ jobs:
|
||||
artifacts: "xen.NewHorizons.zip"
|
||||
draft: true
|
||||
prerelease: false
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
@ -1,9 +1,9 @@
|
||||
ManifestFileVersion: 0
|
||||
CRC: 1013046168
|
||||
CRC: 1613957014
|
||||
Hashes:
|
||||
AssetFileHash:
|
||||
serializedVersion: 2
|
||||
Hash: 0123e044c220152b98ceaf0975b8cadd
|
||||
Hash: 9b2f376d4639a3fa789eadaf132f9889
|
||||
TypeTreeHash:
|
||||
serializedVersion: 2
|
||||
Hash: 10a6a558690295dadb3dd990eda0821a
|
||||
@ -17,7 +17,7 @@ SerializeReferenceClassIdentifiers: []
|
||||
Assets:
|
||||
- Assets/Shaders/SphereTextureWrapper.shader
|
||||
- Assets/Shaders/Ring.shader
|
||||
- Assets/Shaders/SphereTextureWrapperNormal.shader
|
||||
- Assets/Shaders/SphereTextureWrapperTriplanar.shader
|
||||
- Assets/Shaders/UnlitRing1Pixel.shader
|
||||
- Assets/Shaders/UnlitTransparent.shader
|
||||
- Assets/Resources/TransparentCloud.mat
|
||||
|
||||
@ -16,9 +16,10 @@ namespace NewHorizons.Builder.Atmosphere
|
||||
sc.isTrigger = true;
|
||||
sc.radius = config.Atmosphere.size;
|
||||
|
||||
// copied from gd
|
||||
var sfv = airGO.AddComponent<SimpleFluidVolume>();
|
||||
sfv._layer = 5;
|
||||
sfv._priority = 1;
|
||||
sfv._priority = 0;
|
||||
sfv._density = 1.2f;
|
||||
sfv._fluidType = FluidVolume.Type.AIR;
|
||||
sfv._allowShipAutoroll = true;
|
||||
|
||||
@ -126,11 +126,12 @@ namespace NewHorizons.Builder.Atmosphere
|
||||
|
||||
SphereCollider fluidSC = cloudsFluidGO.AddComponent<SphereCollider>();
|
||||
fluidSC.isTrigger = true;
|
||||
fluidSC.radius = atmo.size;
|
||||
fluidSC.radius = atmo.clouds.outerCloudRadius;
|
||||
|
||||
OWShellCollider fluidOWSC = cloudsFluidGO.AddComponent<OWShellCollider>();
|
||||
fluidOWSC._innerRadius = atmo.size * 0.9f;
|
||||
fluidOWSC._innerRadius = atmo.clouds.innerCloudRadius;
|
||||
|
||||
// copied from gd
|
||||
CloudLayerFluidVolume fluidCLFV = cloudsFluidGO.AddComponent<CloudLayerFluidVolume>();
|
||||
fluidCLFV._layer = 5;
|
||||
fluidCLFV._priority = 1;
|
||||
|
||||
@ -243,13 +243,14 @@ namespace NewHorizons.Builder.Body
|
||||
cloak._sectors = new Sector[] { sector };
|
||||
cloak.GetComponent<Renderer>().enabled = true;
|
||||
|
||||
// Cull stuff
|
||||
var cullController = go.AddComponent<BrambleSectorController>();
|
||||
cullController.SetSector(sector);
|
||||
|
||||
// Do next update so other nodes can be built first
|
||||
Delay.FireOnNextUpdate(() =>
|
||||
{
|
||||
// Cull stuff
|
||||
// this in in the delay because it fixes #562
|
||||
var cullController = go.AddComponent<BrambleSectorController>();
|
||||
cullController.SetSector(sector);
|
||||
|
||||
// Prevent recursion from causing hard crash
|
||||
foreach (var senderWarp in outerFogWarpVolume._senderWarps.ToList())
|
||||
{
|
||||
|
||||
@ -9,22 +9,6 @@ namespace NewHorizons.Builder.Body.Geometry
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.name = "CubeSphere";
|
||||
|
||||
float max = 1;
|
||||
if (stretch.x > stretch.y && stretch.x > stretch.z)
|
||||
max = stretch.x;
|
||||
else if (stretch.y > stretch.x && stretch.y > stretch.z)
|
||||
max = stretch.y;
|
||||
else if (stretch.z > stretch.x && stretch.z > stretch.y)
|
||||
max = stretch.z;
|
||||
else if (stretch.y == stretch.z && stretch.x > stretch.y)
|
||||
max = stretch.x;
|
||||
else if (stretch.x == stretch.z && stretch.y > stretch.x)
|
||||
max = stretch.y;
|
||||
else if (stretch.x == stretch.y && stretch.z > stretch.x)
|
||||
max = stretch.z;
|
||||
minHeight /= max;
|
||||
maxHeight /= max;
|
||||
|
||||
CreateVertices(mesh, resolution, heightMap, minHeight, maxHeight);
|
||||
StretchVertices(mesh, stretch);
|
||||
CreateTriangles(mesh, resolution);
|
||||
@ -124,8 +108,7 @@ namespace NewHorizons.Builder.Body.Geometry
|
||||
v.y = v2.y * Mathf.Sqrt(1f - x2 / 2f - z2 / 2f + x2 * z2 / 3f);
|
||||
v.z = v2.z * Mathf.Sqrt(1f - x2 / 2f - y2 / 2f + x2 * y2 / 3f);
|
||||
|
||||
// The shader uses real coords
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(v, false);
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(v, true);
|
||||
float longitude = sphericals.x;
|
||||
float latitude = sphericals.y;
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using NewHorizons.Builder.Body.Geometry;
|
||||
using NewHorizons.External.Modules;
|
||||
using NewHorizons.Utility;
|
||||
using NewHorizons.Utility.Files;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
@ -13,66 +12,42 @@ namespace NewHorizons.Builder.Body
|
||||
public static class HeightMapBuilder
|
||||
{
|
||||
public static Shader PlanetShader;
|
||||
private static readonly int EmissionMap = Shader.PropertyToID("_EmissionMap");
|
||||
private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor");
|
||||
|
||||
// I hate nested functions okay
|
||||
private static IModBehaviour _currentMod;
|
||||
private static string _currentPlanetName;
|
||||
|
||||
public static GameObject Make(GameObject planetGO, Sector sector, HeightMapModule module, IModBehaviour mod, int resolution, bool useLOD = false)
|
||||
{
|
||||
var deleteHeightmapFlag = false;
|
||||
bool deleteHeightmapFlag;
|
||||
|
||||
Texture2D heightMap, textureMap, smoothnessMap, normalMap, emissionMap, tileBlendMap;
|
||||
|
||||
Tile baseTile, redTile, greenTile, blueTile, alphaTile;
|
||||
|
||||
_currentMod = mod;
|
||||
_currentPlanetName = planetGO.name;
|
||||
|
||||
Texture2D heightMap, textureMap, emissionMap;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(module.heightMap) && !File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, module.heightMap)))
|
||||
{
|
||||
NHLogger.LogError($"Bad path for {planetGO.name} heightMap: {module.heightMap} couldn't be found.");
|
||||
module.heightMap = null;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(module.textureMap) && !File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, module.textureMap)))
|
||||
{
|
||||
NHLogger.LogError($"Bad path for {planetGO.name} textureMap: {module.textureMap} couldn't be found.");
|
||||
module.textureMap = null;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(module.emissionMap) && !File.Exists(Path.Combine(mod.ModHelper.Manifest.ModFolderPath, module.emissionMap)))
|
||||
{
|
||||
NHLogger.LogError($"Bad path for {planetGO.name} emissionMap: {module.emissionMap} couldn't be found.");
|
||||
module.emissionMap = null;
|
||||
}
|
||||
// tiles sample from this so we must wrap
|
||||
textureMap = Load(module.textureMap, "textureMap", true, false) ?? Texture2D.whiteTexture;
|
||||
smoothnessMap = Load(module.smoothnessMap, "smoothnessMap", false, false);
|
||||
normalMap = Load(module.normalMap, "normalMap", false, true);
|
||||
emissionMap = Load(module.emissionMap, "emissionMap", false, false);
|
||||
|
||||
if (string.IsNullOrEmpty(module.heightMap))
|
||||
{
|
||||
heightMap = Texture2D.whiteTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO we gotta get this working better
|
||||
// If we've loaded a new heightmap we'll delete the texture after
|
||||
// Only delete it if it wasnt loaded before (something else is using it)
|
||||
deleteHeightmapFlag = !ImageUtilities.IsTextureLoaded(mod, module.heightMap);
|
||||
heightMap = ImageUtilities.GetTexture(mod, module.heightMap);
|
||||
}
|
||||
tileBlendMap = useLOD ? Load(module.tileBlendMap, "tileBlendMap", false, false) : null;
|
||||
|
||||
if (string.IsNullOrEmpty(module.textureMap))
|
||||
{
|
||||
textureMap = Texture2D.whiteTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
textureMap = ImageUtilities.GetTexture(mod, module.textureMap);
|
||||
}
|
||||
baseTile = new Tile(useLOD ? module.baseTile : null, "BASE_TILE", "_BaseTile");
|
||||
redTile = new Tile(useLOD ? module.redTile : null, "RED_TILE", "_RedTile");
|
||||
greenTile = new Tile(useLOD ? module.greenTile : null, "GREEN_TILE", "_GreenTile");
|
||||
blueTile = new Tile(useLOD ? module.blueTile : null, "BLUE_TILE", "_BlueTile");
|
||||
alphaTile = new Tile(useLOD ? module.alphaTile : null, "ALPHA_TILE", "_AlphaTile");
|
||||
|
||||
if (string.IsNullOrEmpty(module.emissionMap))
|
||||
{
|
||||
emissionMap = Texture2D.blackTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
emissionMap = ImageUtilities.GetTexture(mod, module.emissionMap);
|
||||
}
|
||||
// Only delete heightmap if it hasn't been loaded yet
|
||||
deleteHeightmapFlag = !string.IsNullOrEmpty(module.heightMap) && !ImageUtilities.IsTextureLoaded(mod, module.heightMap);
|
||||
|
||||
// If the texturemap is the same as the heightmap don't delete it #176
|
||||
// Do the same with emissionmap
|
||||
if (textureMap == heightMap || emissionMap == heightMap) deleteHeightmapFlag = false;
|
||||
heightMap = Load(module.heightMap, "heightMap", false, false) ?? Texture2D.whiteTexture;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -80,18 +55,20 @@ namespace NewHorizons.Builder.Body
|
||||
return null;
|
||||
}
|
||||
|
||||
_currentMod = null;
|
||||
_currentPlanetName = null;
|
||||
|
||||
var cubeSphere = new GameObject("CubeSphere");
|
||||
cubeSphere.SetActive(false);
|
||||
cubeSphere.transform.parent = sector?.transform ?? planetGO.transform;
|
||||
cubeSphere.transform.SetParent(sector?.transform ?? planetGO.transform, false);
|
||||
|
||||
if (PlanetShader == null) PlanetShader = Main.NHAssetBundle.LoadAsset<Shader>("Assets/Shaders/SphereTextureWrapper.shader");
|
||||
if (PlanetShader == null) PlanetShader = Main.NHAssetBundle.LoadAsset<Shader>("Assets/Shaders/SphereTextureWrapperTriplanar.shader");
|
||||
|
||||
var stretch = module.stretch != null ? (Vector3)module.stretch : Vector3.one;
|
||||
|
||||
var emissionColor = module.emissionColor != null ? module.emissionColor.ToColor() : Color.white;
|
||||
var emissionColor = module.emissionColor?.ToColor() ?? Color.white;
|
||||
|
||||
var level1 = MakeLODTerrain(cubeSphere, heightMap, textureMap, module.minHeight, module.maxHeight, resolution, stretch,
|
||||
emissionMap, emissionColor);
|
||||
var level1 = MakeLODTerrain(resolution, useLOD);
|
||||
|
||||
var cubeSphereMC = cubeSphere.AddComponent<MeshCollider>();
|
||||
cubeSphereMC.sharedMesh = level1.gameObject.GetComponent<MeshFilter>().mesh;
|
||||
@ -99,8 +76,7 @@ namespace NewHorizons.Builder.Body
|
||||
if (useLOD)
|
||||
{
|
||||
var level2Res = (int)Mathf.Clamp(resolution / 2f, 1 /*cube moment*/, 100);
|
||||
var level2 = MakeLODTerrain(cubeSphere, heightMap, textureMap, module.minHeight, module.maxHeight, level2Res, stretch,
|
||||
emissionMap, emissionColor);
|
||||
var level2 = MakeLODTerrain(level2Res, false);
|
||||
|
||||
var LODGroup = cubeSphere.AddComponent<LODGroup>();
|
||||
LODGroup.size = module.maxHeight;
|
||||
@ -118,42 +94,107 @@ namespace NewHorizons.Builder.Body
|
||||
}
|
||||
|
||||
var cubeSphereSC = cubeSphere.AddComponent<SphereCollider>();
|
||||
cubeSphereSC.radius = Mathf.Min(module.minHeight, module.maxHeight);
|
||||
cubeSphereSC.radius = Mathf.Min(module.minHeight, module.maxHeight) * Mathf.Min(stretch.x, stretch.y, stretch.z);
|
||||
|
||||
var superGroup = planetGO.GetComponent<ProxyShadowCasterSuperGroup>();
|
||||
if (superGroup != null) cubeSphere.AddComponent<ProxyShadowCaster>()._superGroup = superGroup;
|
||||
|
||||
// Fix rotation in the end
|
||||
// 90 degree rotation around x is because cube sphere uses Z as up, Unity uses Y
|
||||
cubeSphere.transform.rotation = planetGO.transform.TransformRotation(Quaternion.Euler(90, 0, 0));
|
||||
cubeSphere.transform.position = planetGO.transform.position;
|
||||
|
||||
cubeSphere.SetActive(true);
|
||||
|
||||
// Now that we've made the mesh we can delete the heightmap texture
|
||||
if (deleteHeightmapFlag) ImageUtilities.DeleteTexture(mod, module.heightMap, heightMap);
|
||||
|
||||
return cubeSphere;
|
||||
}
|
||||
|
||||
private static MeshRenderer MakeLODTerrain(GameObject root, Texture2D heightMap, Texture2D textureMap, float minHeight, float maxHeight, int resolution, Vector3 stretch, Texture2D emissionMap, Color emissionColor)
|
||||
MeshRenderer MakeLODTerrain(int resolution, bool useTriplanar)
|
||||
{
|
||||
var LODCubeSphere = new GameObject("LODCubeSphere");
|
||||
LODCubeSphere.transform.SetParent(cubeSphere.transform, false);
|
||||
|
||||
LODCubeSphere.AddComponent<MeshFilter>().mesh = CubeSphere.Build(resolution, heightMap, minHeight, maxHeight, stretch);
|
||||
LODCubeSphere.AddComponent<MeshFilter>().mesh = CubeSphere.Build(resolution, heightMap, module.minHeight, module.maxHeight, stretch);
|
||||
|
||||
var cubeSphereMR = LODCubeSphere.AddComponent<MeshRenderer>();
|
||||
var material = new Material(PlanetShader);
|
||||
cubeSphereMR.material = material;
|
||||
material.name = textureMap.name;
|
||||
material.mainTexture = textureMap;
|
||||
material.SetTexture(EmissionMap, emissionMap);
|
||||
material.SetColor(EmissionColor, emissionColor);
|
||||
|
||||
LODCubeSphere.transform.parent = root.transform;
|
||||
LODCubeSphere.transform.localPosition = Vector3.zero;
|
||||
material.mainTexture = textureMap;
|
||||
material.SetFloat("_Smoothness", module.smoothness);
|
||||
material.SetFloat("_Metallic", module.metallic);
|
||||
material.SetTexture("_SmoothnessMap", smoothnessMap);
|
||||
material.SetFloat("_BumpStrength", module.normalStrength);
|
||||
material.SetTexture("_BumpMap", normalMap);
|
||||
material.SetColor("_EmissionColor", emissionColor);
|
||||
material.SetTexture("_EmissionMap", emissionMap);
|
||||
|
||||
if (useTriplanar)
|
||||
{
|
||||
material.SetTexture("_BlendMap", tileBlendMap);
|
||||
|
||||
baseTile.TryApplyTile(material);
|
||||
redTile.TryApplyTile(material);
|
||||
greenTile.TryApplyTile(material);
|
||||
blueTile.TryApplyTile(material);
|
||||
alphaTile.TryApplyTile(material);
|
||||
}
|
||||
|
||||
return cubeSphereMR;
|
||||
}
|
||||
}
|
||||
|
||||
private static Texture2D Load(string path, string name, bool wrap, bool linear)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) return null;
|
||||
|
||||
if (!File.Exists(Path.Combine(_currentMod.ModHelper.Manifest.ModFolderPath, path)))
|
||||
{
|
||||
NHLogger.LogError($"Bad path for {_currentPlanetName} {name}: {path} couldn't be found.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return ImageUtilities.GetTexture(_currentMod, path, wrap: wrap, linear: linear);
|
||||
}
|
||||
|
||||
private readonly struct Tile
|
||||
{
|
||||
private readonly HeightMapModule.HeightMapTileInfo _info;
|
||||
private readonly string _keyword, _prefix;
|
||||
private readonly Texture2D _texture, _smoothness, _normal;
|
||||
|
||||
public Tile(HeightMapModule.HeightMapTileInfo info, string keyword, string prefix)
|
||||
{
|
||||
_info = info;
|
||||
|
||||
_keyword = keyword;
|
||||
_prefix = prefix;
|
||||
|
||||
if (_info != null)
|
||||
{
|
||||
_texture = Load(info.textureTile, $"{_prefix}TextureTile", true, false);
|
||||
_smoothness = Load(info.smoothnessTile, $"{_prefix}SmoothnessTile", true, false);
|
||||
_normal = Load(info.normalTile, $"{_prefix}NormalTile", true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Visual studio won't compile if you don't do this idk
|
||||
_texture = _smoothness = _normal = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void TryApplyTile(Material material)
|
||||
{
|
||||
if (_info != null)
|
||||
{
|
||||
material.SetFloat(_prefix, 1);
|
||||
material.EnableKeyword(_keyword);
|
||||
|
||||
material.SetFloat($"{_prefix}Scale", 1 / _info.size);
|
||||
material.SetTexture($"{_prefix}Albedo", _texture);
|
||||
material.SetTexture($"{_prefix}SmoothnessMap", _smoothness);
|
||||
material.SetFloat($"{_prefix}BumpStrength", _info.normalStrength);
|
||||
material.SetTexture($"{_prefix}BumpMap", _normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ namespace NewHorizons.Builder.Body
|
||||
private static GameObject _supernovaPrefab;
|
||||
private static Material _mainSequenceMaterial;
|
||||
private static Material _giantMaterial;
|
||||
private static Material _flareMaterial;
|
||||
|
||||
private static bool _isInit;
|
||||
|
||||
@ -54,6 +55,11 @@ namespace NewHorizons.Builder.Body
|
||||
if (_supernovaPrefab == null) _supernovaPrefab = SearchUtilities.Find("Sun_Body/Sector_SUN/Effects_SUN/Supernova").InstantiateInactive().Rename("Prefab_Supernova").DontDestroyOnLoad();
|
||||
if (_mainSequenceMaterial == null) _mainSequenceMaterial = new Material(SearchUtilities.Find("Sun_Body").GetComponent<SunController>()._startSurfaceMaterial).DontDestroyOnLoad();
|
||||
if (_giantMaterial == null) _giantMaterial = new Material(SearchUtilities.Find("Sun_Body").GetComponent<SunController>()._endSurfaceMaterial).DontDestroyOnLoad();
|
||||
if (_flareMaterial == null)
|
||||
{
|
||||
_flareMaterial = new Material(_starSolarFlareEmitter.GetComponentInChildren<SolarFlareController>().GetComponent<MeshRenderer>().sharedMaterial).DontDestroyOnLoad();
|
||||
_flareMaterial.color = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
public static (GameObject, StarController, StarEvolutionController, Light) Make(GameObject planetGO, Sector sector, StarModule starModule, IModBehaviour mod, bool isStellarRemnant)
|
||||
@ -347,11 +353,11 @@ namespace NewHorizons.Builder.Body
|
||||
var flareTint = starModule.tint.ToColor();
|
||||
var emitter = solarFlareEmitter.GetComponent<SolarFlareEmitter>();
|
||||
emitter.tint = flareTint;
|
||||
var material = new Material(_flareMaterial);
|
||||
foreach (var controller in solarFlareEmitter.GetComponentsInChildren<SolarFlareController>())
|
||||
{
|
||||
// It multiplies color by tint but wants something very bright idk
|
||||
controller._color = new Color(1, 1, 1);
|
||||
controller.GetComponent<MeshRenderer>().sharedMaterial.SetColor("_Color", controller._color);
|
||||
controller.GetComponent<MeshRenderer>().sharedMaterial = material;
|
||||
controller._color = Color.white;
|
||||
controller._tint = flareTint;
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ namespace NewHorizons.Builder.Body
|
||||
buoyancyObject.layer = Layer.BasicEffectVolume;
|
||||
|
||||
var sphereCollider = buoyancyObject.AddComponent<SphereCollider>();
|
||||
sphereCollider.radius = 1;
|
||||
sphereCollider.radius = 1; // scaled by localScale
|
||||
sphereCollider.isTrigger = true;
|
||||
|
||||
var owCollider = buoyancyObject.AddComponent<OWCollider>();
|
||||
@ -114,6 +114,7 @@ namespace NewHorizons.Builder.Body
|
||||
var buoyancyTriggerVolume = buoyancyObject.AddComponent<OWTriggerVolume>();
|
||||
buoyancyTriggerVolume._owCollider = owCollider;
|
||||
|
||||
// copied from gd
|
||||
var fluidVolume = buoyancyObject.AddComponent<RadialFluidVolume>();
|
||||
fluidVolume._fluidType = FluidVolume.Type.WATER;
|
||||
fluidVolume._attachedBody = rb;
|
||||
@ -121,7 +122,10 @@ namespace NewHorizons.Builder.Body
|
||||
fluidVolume._radius = waterSize;
|
||||
fluidVolume._buoyancyDensity = module.buoyancy;
|
||||
fluidVolume._density = module.density;
|
||||
fluidVolume._layer = LayerMask.NameToLayer("BasicEffectVolume");
|
||||
fluidVolume._layer = 5;
|
||||
fluidVolume._priority = 3;
|
||||
fluidVolume._allowShipAutoroll = true;
|
||||
fluidVolume._disableOnStart = false;
|
||||
|
||||
var fogGO = Object.Instantiate(_oceanFog, waterGO.transform);
|
||||
fogGO.name = "OceanFog";
|
||||
|
||||
@ -34,9 +34,16 @@ namespace NewHorizons.Builder.General
|
||||
if (config.tint != null)
|
||||
{
|
||||
var tint = config.tint.ToColor();
|
||||
var key = $"AmbientLight_QM > tint {tint}";
|
||||
if (ImageUtilities.CheckCachedTexture(key, out var existingTexture))
|
||||
{
|
||||
light.cookie = existingTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
var baseCubemap = Main.NHPrivateAssetBundle.LoadAsset<Cubemap>("AmbientLight_QM");
|
||||
var cubemap = new Cubemap(baseCubemap.width, baseCubemap.format, baseCubemap.mipmapCount != 1);
|
||||
cubemap.name = baseCubemap.name + "Tinted";
|
||||
cubemap.name = key;
|
||||
cubemap.wrapMode = baseCubemap.wrapMode;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
@ -51,10 +58,11 @@ namespace NewHorizons.Builder.General
|
||||
cubemap.SetPixels(newColors, cubemapFace);
|
||||
}
|
||||
cubemap.Apply();
|
||||
ImageUtilities.TrackGeneratedTexture(cubemap);
|
||||
ImageUtilities.TrackCachedTexture(key, cubemap);
|
||||
|
||||
light.cookie = cubemap;
|
||||
}
|
||||
}
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
@ -35,8 +35,9 @@ namespace NewHorizons.Builder.General
|
||||
|
||||
var owTriggerVolume = gravityGO.AddComponent<OWTriggerVolume>();
|
||||
|
||||
// copied from th and qm
|
||||
var gravityVolume = gravityGO.AddComponent<GravityVolume>();
|
||||
gravityVolume._cutoffAcceleration = 0.1f;
|
||||
gravityVolume._cutoffAcceleration = 0f;
|
||||
|
||||
var falloff = config.Base.gravityFallOff == GravityFallOff.Linear? GravityVolume.FalloffType.linear : GravityVolume.FalloffType.inverseSquared;
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@ using OWML.Utils;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using NewHorizons.External.Modules.Props.Audio;
|
||||
using System.Linq;
|
||||
|
||||
namespace NewHorizons.Builder.Props.Audio
|
||||
{
|
||||
@ -17,8 +19,8 @@ namespace NewHorizons.Builder.Props.Audio
|
||||
|
||||
public static int NumberOfFrequencies;
|
||||
|
||||
private static HashSet<SignalName> _qmSignals;
|
||||
private static HashSet<SignalName> _cloakedSignals;
|
||||
private static HashSet<AudioSignal> _qmSignals;
|
||||
private static HashSet<AudioSignal> _cloakedSignals;
|
||||
|
||||
public static bool Initialized;
|
||||
|
||||
@ -33,7 +35,7 @@ namespace NewHorizons.Builder.Props.Audio
|
||||
};
|
||||
NumberOfFrequencies = EnumUtils.GetValues<SignalFrequency>().Length;
|
||||
|
||||
_qmSignals = new() { SignalName.Quantum_QM };
|
||||
_qmSignals = new (){ SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent<AudioSignal>() };
|
||||
_cloakedSignals = new();
|
||||
|
||||
Initialized = true;
|
||||
@ -67,14 +69,14 @@ namespace NewHorizons.Builder.Props.Audio
|
||||
|
||||
public static bool IsFrequencyInUse(SignalFrequency freq) => _frequenciesInUse.Contains(freq);
|
||||
|
||||
public static bool IsCloaked(this SignalName signalName)
|
||||
public static bool IsCloaked(this AudioSignal signal)
|
||||
{
|
||||
return _cloakedSignals.Contains(signalName);
|
||||
return _cloakedSignals.Contains(signal);
|
||||
}
|
||||
|
||||
public static bool IsOnQuantumMoon(this SignalName signalName)
|
||||
public static bool IsOnQuantumMoon(this AudioSignal signal)
|
||||
{
|
||||
return _qmSignals.Contains(signalName);
|
||||
return _qmSignals.Contains(signal);
|
||||
}
|
||||
|
||||
public static SignalFrequency AddFrequency(string str)
|
||||
@ -175,8 +177,8 @@ namespace NewHorizons.Builder.Props.Audio
|
||||
signalGO.SetActive(true);
|
||||
|
||||
// Track certain special signal things
|
||||
if (planetGO.GetComponent<AstroObject>()?.GetAstroObjectName() == AstroObject.Name.QuantumMoon) _qmSignals.Add(name);
|
||||
if (info.insideCloak) _cloakedSignals.Add(name);
|
||||
if (planetGO.GetComponent<AstroObject>()?.GetAstroObjectName() == AstroObject.Name.QuantumMoon) _qmSignals.Add(audioSignal);
|
||||
if (info.insideCloak) _cloakedSignals.Add(audioSignal);
|
||||
|
||||
_frequenciesInUse.Add(frequency);
|
||||
|
||||
|
||||
@ -255,7 +255,9 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
else if(component is SectoredMonoBehaviour behaviour)
|
||||
{
|
||||
behaviour.SetSector(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
|
||||
behaviour._sector = sector;
|
||||
}
|
||||
|
||||
else if(component is OWItemSocket socket)
|
||||
@ -345,8 +347,9 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
else if (component is NomaiInterfaceOrb orb)
|
||||
{
|
||||
orb._parentAstroObject = planetGO.GetComponent<AstroObject>();
|
||||
orb._parentBody = planetGO.GetComponent<OWRigidbody>();
|
||||
// detect planet gravity
|
||||
var gravityVolume = planetGO.GetAttachedOWRigidbody().GetAttachedGravityVolume();
|
||||
orb.GetComponent<ConstantForceDetector>()._detectableFields = gravityVolume ? new ForceVolume[] { gravityVolume } : new ForceVolume[] { };
|
||||
}
|
||||
|
||||
else if (component is VisionTorchItem torchItem)
|
||||
@ -363,7 +366,7 @@ namespace NewHorizons.Builder.Props
|
||||
else if(component is Shape shape) shape.enabled = true;
|
||||
|
||||
// If it's not a moving anglerfish make sure the anim controller is regular
|
||||
else if(component is AnglerfishAnimController && component.GetComponentInParent<AnglerfishController>() == null)
|
||||
else if(component is AnglerfishAnimController && component.transform.parent.GetComponent<AnglerfishController>() == null) //Manual parent chain so we can find inactive
|
||||
{
|
||||
component.gameObject.AddComponent<AnglerAnimFixer>();
|
||||
}
|
||||
|
||||
@ -147,6 +147,7 @@ namespace NewHorizons.Builder.Props
|
||||
var controller = character.GetComponent<CharacterAnimController>();
|
||||
var traveler = character.GetComponent<TravelerController>();
|
||||
var travelerEye = character.GetComponent<TravelerEyeController>();
|
||||
var hearthianRecorder = character.GetComponent<HearthianRecorderEffects>();
|
||||
|
||||
var lookOnlyWhenTalking = info.lookAtRadius <= 0;
|
||||
|
||||
@ -196,6 +197,34 @@ namespace NewHorizons.Builder.Props
|
||||
dialogue.OnEndConversation += nomaiController.StopWatchingPlayer;
|
||||
}
|
||||
}
|
||||
else if (hearthianRecorder != null)
|
||||
{
|
||||
Delay.FireOnNextUpdate(() =>
|
||||
{
|
||||
// #520
|
||||
if (hearthianRecorder._characterDialogueTree != null)
|
||||
{
|
||||
hearthianRecorder._characterDialogueTree.OnStartConversation -= hearthianRecorder.OnPlayRecorder;
|
||||
hearthianRecorder._characterDialogueTree.OnEndConversation -= hearthianRecorder.OnStopRecorder;
|
||||
}
|
||||
|
||||
// Recorder props have their own dialogue on them already
|
||||
// Make sure to delete it when we're trying to connect new dialogue to it
|
||||
var existingDialogue = hearthianRecorder.GetComponent<CharacterDialogueTree>();
|
||||
if (existingDialogue != dialogue && existingDialogue != null)
|
||||
{
|
||||
// Can't delete the existing dialogue because its a required component but we can make it unable to select at least
|
||||
GameObject.Destroy(hearthianRecorder.GetComponent<OWCollider>());
|
||||
GameObject.Destroy(hearthianRecorder.GetComponent<SphereCollider>());
|
||||
GameObject.Destroy(existingDialogue._interactVolume);
|
||||
existingDialogue.enabled = false;
|
||||
}
|
||||
|
||||
hearthianRecorder._characterDialogueTree = dialogue;
|
||||
hearthianRecorder._characterDialogueTree.OnStartConversation += hearthianRecorder.OnPlayRecorder;
|
||||
hearthianRecorder._characterDialogueTree.OnEndConversation += hearthianRecorder.OnStopRecorder;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// If they have nothing else just put the face player when talking thing on them
|
||||
|
||||
@ -29,8 +29,9 @@ namespace NewHorizons.Builder.Props
|
||||
private static GameObject _scrollPrefab;
|
||||
private static GameObject _computerPrefab;
|
||||
private static GameObject _preCrashComputerPrefab;
|
||||
private static GameObject _cairnPrefab;
|
||||
private static GameObject _cairnVariantPrefab;
|
||||
private static GameObject _cairnBHPrefab;
|
||||
private static GameObject _cairnTHPrefab;
|
||||
private static GameObject _cairnCTPrefab;
|
||||
private static GameObject _recorderPrefab;
|
||||
private static GameObject _preCrashRecorderPrefab;
|
||||
private static GameObject _trailmarkerPrefab;
|
||||
@ -121,16 +122,22 @@ namespace NewHorizons.Builder.Props
|
||||
_preCrashComputerPrefab.transform.rotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
if (_cairnPrefab == null)
|
||||
if (_cairnBHPrefab == null)
|
||||
{
|
||||
_cairnPrefab = SearchUtilities.Find("BrittleHollow_Body/Sector_BH/Sector_Crossroads/Interactables_Crossroads/Trailmarkers/Prefab_NOM_BH_Cairn_Arc (1)").InstantiateInactive().Rename("Prefab_NOM_Cairn").DontDestroyOnLoad();
|
||||
_cairnPrefab.transform.rotation = Quaternion.identity;
|
||||
_cairnBHPrefab = SearchUtilities.Find("BrittleHollow_Body/Sector_BH/Sector_Crossroads/Interactables_Crossroads/Trailmarkers/Prefab_NOM_BH_Cairn_Arc (1)").InstantiateInactive().Rename("Prefab_NOM_BH_Cairn").DontDestroyOnLoad();
|
||||
_cairnBHPrefab.transform.rotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
if (_cairnVariantPrefab == null)
|
||||
if (_cairnTHPrefab == null)
|
||||
{
|
||||
_cairnVariantPrefab = SearchUtilities.Find("TimberHearth_Body/Sector_TH/Sector_NomaiMines/Interactables_NomaiMines/Prefab_NOM_TH_Cairn_Arc").InstantiateInactive().Rename("Prefab_NOM_Cairn").DontDestroyOnLoad();
|
||||
_cairnVariantPrefab.transform.rotation = Quaternion.identity;
|
||||
_cairnTHPrefab = SearchUtilities.Find("TimberHearth_Body/Sector_TH/Sector_NomaiMines/Interactables_NomaiMines/Prefab_NOM_TH_Cairn_Arc").InstantiateInactive().Rename("Prefab_NOM_TH_Cairn").DontDestroyOnLoad();
|
||||
_cairnTHPrefab.transform.rotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
if (_cairnCTPrefab == null)
|
||||
{
|
||||
_cairnCTPrefab = SearchUtilities.Find("CaveTwin_Body/Sector_CaveTwin/Sector_NorthHemisphere/Sector_NorthSurface/Sector_TimeLoopExperiment/Interactables_TimeLoopExperiment/Prefab_NOM_CT_Cairn_Arc").InstantiateInactive().Rename("Prefab_NOM_CT_Cairn").DontDestroyOnLoad();
|
||||
_cairnCTPrefab.transform.rotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
if (_recorderPrefab == null)
|
||||
@ -410,19 +417,16 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
return computerObject;
|
||||
}
|
||||
case NomaiTextType.Cairn:
|
||||
case NomaiTextType.CairnVariant:
|
||||
case NomaiTextType.CairnBrittleHollow:
|
||||
case NomaiTextType.CairnTimberHearth:
|
||||
case NomaiTextType.CairnEmberTwin:
|
||||
{
|
||||
var cairnObject = (info.type == NomaiTextType.CairnVariant ? _cairnVariantPrefab : _cairnPrefab).InstantiateInactive();
|
||||
var cairnObject = (info.type == NomaiTextType.CairnTimberHearth ? _cairnTHPrefab : (info.type == NomaiTextType.CairnEmberTwin ? _cairnCTPrefab : _cairnBHPrefab)).InstantiateInactive();
|
||||
|
||||
if (!string.IsNullOrEmpty(info.rename))
|
||||
{
|
||||
cairnObject.name = info.rename;
|
||||
}
|
||||
else
|
||||
{
|
||||
cairnObject.name = _cairnPrefab.name;
|
||||
}
|
||||
|
||||
cairnObject.transform.parent = sector?.transform ?? planetGO.transform;
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ 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;
|
||||
@ -11,6 +10,7 @@ using System.Linq;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace NewHorizons.Builder.Props
|
||||
{
|
||||
public static class ScatterBuilder
|
||||
@ -23,6 +23,7 @@ namespace NewHorizons.Builder.Props
|
||||
private static void MakeScatter(GameObject go, ScatterInfo[] scatterInfo, float radius, Sector sector, IModBehaviour mod, PlanetConfig config)
|
||||
{
|
||||
var heightMap = config.HeightMap;
|
||||
var deleteHeightmapFlag = false;
|
||||
|
||||
var makeFibonacciSphere = scatterInfo.Any(x => x.preventOverlap);
|
||||
|
||||
@ -46,10 +47,8 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
if (!string.IsNullOrEmpty(heightMap.heightMap))
|
||||
{
|
||||
// TODO copy what heightmap builder does eventually
|
||||
deleteHeightmapFlag = !ImageUtilities.IsTextureLoaded(mod, heightMap.heightMap);
|
||||
heightMapTexture = ImageUtilities.GetTexture(mod, heightMap.heightMap);
|
||||
// defer remove texture to next frame
|
||||
Delay.FireOnNextUpdate(() => Object.Destroy(heightMapTexture));
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
@ -63,7 +62,7 @@ namespace NewHorizons.Builder.Props
|
||||
{
|
||||
Random.InitState(propInfo.seed);
|
||||
|
||||
// By default don't put underwater more than a mater
|
||||
// By default don't put underwater more than a meter
|
||||
// this is a backward compat thing lol
|
||||
if (config.Water != null && propInfo.minHeight == null) propInfo.minHeight = config.Water.size - 1f;
|
||||
|
||||
@ -98,7 +97,7 @@ namespace NewHorizons.Builder.Props
|
||||
var height = radius;
|
||||
if (heightMapTexture != null)
|
||||
{
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(point, false);
|
||||
var sphericals = CoordinateUtilities.CartesianToSpherical(point, true);
|
||||
float longitude = sphericals.x;
|
||||
float latitude = sphericals.y;
|
||||
|
||||
@ -119,9 +118,6 @@ namespace NewHorizons.Builder.Props
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Because heightmaps are dumb gotta rotate it 90 degrees around the x axis bc UHHHHHHHHHHHHH
|
||||
point = Quaternion.Euler(90, 0, 0) * point;
|
||||
}
|
||||
|
||||
var prop = scatterPrefab.InstantiateInactive();
|
||||
@ -140,6 +136,11 @@ namespace NewHorizons.Builder.Props
|
||||
}
|
||||
|
||||
Object.Destroy(scatterPrefab);
|
||||
|
||||
if (deleteHeightmapFlag && heightMapTexture != null)
|
||||
{
|
||||
ImageUtilities.DeleteTexture(mod, heightMap.heightMap, heightMapTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,8 +27,9 @@ namespace NewHorizons.Builder.Props.TranslatorText
|
||||
private static GameObject _scrollPrefab;
|
||||
public static GameObject ComputerPrefab { get; private set; }
|
||||
private static GameObject _preCrashComputerPrefab;
|
||||
private static GameObject _cairnPrefab;
|
||||
private static GameObject _cairnVariantPrefab;
|
||||
private static GameObject _cairnBHPrefab;
|
||||
private static GameObject _cairnTHPrefab;
|
||||
private static GameObject _cairnCTPrefab;
|
||||
private static GameObject _recorderPrefab;
|
||||
private static GameObject _preCrashRecorderPrefab;
|
||||
private static GameObject _trailmarkerPrefab;
|
||||
@ -93,14 +94,19 @@ namespace NewHorizons.Builder.Props.TranslatorText
|
||||
_preCrashComputerPrefab = SearchUtilities.Find("BrittleHollow_Body/Sector_BH/Sector_EscapePodCrashSite/Sector_CrashFragment/EscapePod_Socket/Interactibles_EscapePod/Prefab_NOM_Vessel_Computer").InstantiateInactive().Rename("Prefab_NOM_Vessel_Computer").DontDestroyOnLoad();
|
||||
}
|
||||
|
||||
if (_cairnPrefab == null)
|
||||
if (_cairnBHPrefab == null)
|
||||
{
|
||||
_cairnPrefab = SearchUtilities.Find("BrittleHollow_Body/Sector_BH/Sector_Crossroads/Interactables_Crossroads/Trailmarkers/Prefab_NOM_BH_Cairn_Arc (1)").InstantiateInactive().Rename("Prefab_NOM_Cairn").DontDestroyOnLoad();
|
||||
_cairnBHPrefab = SearchUtilities.Find("BrittleHollow_Body/Sector_BH/Sector_Crossroads/Interactables_Crossroads/Trailmarkers/Prefab_NOM_BH_Cairn_Arc (1)").InstantiateInactive().Rename("Prefab_NOM_BH_Cairn").DontDestroyOnLoad();
|
||||
}
|
||||
|
||||
if (_cairnVariantPrefab == null)
|
||||
if (_cairnTHPrefab == null)
|
||||
{
|
||||
_cairnVariantPrefab = SearchUtilities.Find("TimberHearth_Body/Sector_TH/Sector_NomaiMines/Interactables_NomaiMines/Prefab_NOM_TH_Cairn_Arc").InstantiateInactive().Rename("Prefab_NOM_Cairn").DontDestroyOnLoad();
|
||||
_cairnTHPrefab = SearchUtilities.Find("TimberHearth_Body/Sector_TH/Sector_NomaiMines/Interactables_NomaiMines/Prefab_NOM_TH_Cairn_Arc").InstantiateInactive().Rename("Prefab_NOM_TH_Cairn").DontDestroyOnLoad();
|
||||
}
|
||||
|
||||
if (_cairnCTPrefab == null)
|
||||
{
|
||||
_cairnCTPrefab = SearchUtilities.Find("CaveTwin_Body/Sector_CaveTwin/Sector_NorthHemisphere/Sector_NorthSurface/Sector_TimeLoopExperiment/Interactables_TimeLoopExperiment/Prefab_NOM_CT_Cairn_Arc").InstantiateInactive().Rename("Prefab_NOM_CT_Cairn").DontDestroyOnLoad();
|
||||
}
|
||||
|
||||
if (_recorderPrefab == null)
|
||||
@ -269,11 +275,12 @@ namespace NewHorizons.Builder.Props.TranslatorText
|
||||
|
||||
return computerObject;
|
||||
}
|
||||
case NomaiTextType.Cairn:
|
||||
case NomaiTextType.CairnVariant:
|
||||
case NomaiTextType.CairnBrittleHollow:
|
||||
case NomaiTextType.CairnTimberHearth:
|
||||
case NomaiTextType.CairnEmberTwin:
|
||||
{
|
||||
var cairnPrefab = info.type == NomaiTextType.CairnVariant ? _cairnVariantPrefab : _cairnPrefab;
|
||||
var cairnObject = GeneralPropBuilder.MakeFromPrefab(cairnPrefab, _cairnPrefab.name, planetGO, sector, info);
|
||||
var cairnPrefab = info.type == NomaiTextType.CairnTimberHearth ? _cairnTHPrefab : (info.type == NomaiTextType.CairnEmberTwin ? _cairnCTPrefab : _cairnBHPrefab);
|
||||
var cairnObject = GeneralPropBuilder.MakeFromPrefab(cairnPrefab, cairnPrefab.name, planetGO, sector, info);
|
||||
|
||||
// Idk do we have to set it active before finding things?
|
||||
cairnObject.SetActive(true);
|
||||
|
||||
@ -44,8 +44,14 @@ public class AddPhysics : MonoBehaviour
|
||||
bodyGo.tag = "DynamicPropDetector";
|
||||
// this collider is not included in groups. oh well
|
||||
bodyGo.AddComponent<SphereCollider>().radius = Radius;
|
||||
var shape = bodyGo.AddComponent<SphereShape>();
|
||||
shape._collisionMode = Shape.CollisionMode.Detector;
|
||||
shape._layerMask = (int)(Shape.Layer.Default | Shape.Layer.Gravity);
|
||||
shape._radius = Radius;
|
||||
bodyGo.AddComponent<DynamicForceDetector>();
|
||||
bodyGo.AddComponent<DynamicFluidDetector>();
|
||||
var fluidDetector = bodyGo.AddComponent<DynamicFluidDetector>();
|
||||
fluidDetector._buoyancy = Locator.GetProbe().GetOWRigidbody()._attachedFluidDetector._buoyancy;
|
||||
fluidDetector._splashEffects = Locator.GetProbe().GetOWRigidbody()._attachedFluidDetector._splashEffects;
|
||||
|
||||
var impactSensor = bodyGo.AddComponent<ImpactSensor>();
|
||||
var audioSource = bodyGo.AddComponent<AudioSource>();
|
||||
|
||||
@ -39,8 +39,10 @@ namespace NewHorizons.Components.SizeControllers
|
||||
|
||||
private void UpdateTargetPositions()
|
||||
{
|
||||
var toPrimary = (_body.transform.position - _dustTargetBody.transform.position).normalized;
|
||||
var velocityDirection = (_primaryBody?.GetVelocity() ?? Vector3.zero) -_body.GetVelocity(); // Accept that this is flipped ok
|
||||
// body is null for proxies
|
||||
// TODO: this will make proxy tails face the real body rather than proxy body (ie wrong). fix properly in a different PR
|
||||
var toPrimary = ((_body ? _body.transform : transform).position - _dustTargetBody.transform.position).normalized;
|
||||
var velocityDirection = (_primaryBody?.GetVelocity() ?? Vector3.zero) - (_body ? _body.GetVelocity() : Vector3.zero); // Accept that this is flipped ok
|
||||
|
||||
var tangentVel = Vector3.ProjectOnPlane(velocityDirection, toPrimary) / velocityDirection.magnitude;
|
||||
|
||||
|
||||
28
NewHorizons/External/Configs/PlanetConfig.cs
vendored
28
NewHorizons/External/Configs/PlanetConfig.cs
vendored
@ -579,6 +579,34 @@ namespace NewHorizons.External.Configs
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Props?.nomaiText != null)
|
||||
{
|
||||
foreach (var nomaiText in Props.nomaiText)
|
||||
{
|
||||
if (nomaiText.type == Modules.TranslatorText.NomaiTextType.Cairn)
|
||||
{
|
||||
nomaiText.type = Modules.TranslatorText.NomaiTextType.CairnBrittleHollow;
|
||||
}
|
||||
else if (nomaiText.type == Modules.TranslatorText.NomaiTextType.CairnVariant)
|
||||
{
|
||||
nomaiText.type = Modules.TranslatorText.NomaiTextType.CairnTimberHearth;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Props?.translatorText != null)
|
||||
{
|
||||
foreach (var translatorText in Props.translatorText)
|
||||
{
|
||||
if (translatorText.type == Modules.TranslatorText.NomaiTextType.Cairn)
|
||||
{
|
||||
translatorText.type = Modules.TranslatorText.NomaiTextType.CairnBrittleHollow;
|
||||
}
|
||||
else if (translatorText.type == Modules.TranslatorText.NomaiTextType.CairnVariant)
|
||||
{
|
||||
translatorText.type = Modules.TranslatorText.NomaiTextType.CairnTimberHearth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Base.hasCometTail)
|
||||
{
|
||||
|
||||
@ -120,7 +120,7 @@ namespace NewHorizons.External.Modules
|
||||
/// <summary>
|
||||
/// Fluid type for sounds/effects when colliding with this cloud.
|
||||
/// </summary>
|
||||
[DefaultValue("cloud")] public NHFluidType fluidType = NHFluidType.Cloud;
|
||||
[DefaultValue("cloud")] public NHFluidType fluidType = NHFluidType.CLOUD;
|
||||
|
||||
/// <summary>
|
||||
/// Add lightning to this planet like on Giant's Deep.
|
||||
|
||||
2
NewHorizons/External/Modules/BaseModule.cs
vendored
2
NewHorizons/External/Modules/BaseModule.cs
vendored
@ -69,7 +69,7 @@ namespace NewHorizons.External.Modules
|
||||
/// <summary>
|
||||
/// Optional. You can force this planet's gravity to be felt over other gravity/zero-gravity sources by increasing this number.
|
||||
/// </summary>
|
||||
public int gravityVolumePriority;
|
||||
[DefaultValue(0)] public int gravityVolumePriority = 0;
|
||||
|
||||
#region Obsolete
|
||||
|
||||
|
||||
117
NewHorizons/External/Modules/HeightMapModule.cs
vendored
117
NewHorizons/External/Modules/HeightMapModule.cs
vendored
@ -28,11 +28,6 @@ namespace NewHorizons.External.Modules
|
||||
/// </summary>
|
||||
public MVector3 stretch;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for the terrain.
|
||||
/// </summary>
|
||||
public string textureMap;
|
||||
|
||||
/// <summary>
|
||||
/// Resolution of the heightmap.
|
||||
/// Higher values means more detail but also more memory/cpu/gpu usage.
|
||||
@ -42,6 +37,44 @@ namespace NewHorizons.External.Modules
|
||||
[DefaultValue(51 * 4)]
|
||||
public int resolution = 51 * 4;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for the terrain colors.
|
||||
/// </summary>
|
||||
public string textureMap;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for the terrain's smoothness and metallic, which are controlled by the texture's alpha and red channels respectively. Optional.
|
||||
/// Typically black with variable transparency, when metallic isn't wanted.
|
||||
/// </summary>
|
||||
public string smoothnessMap;
|
||||
|
||||
/// <summary>
|
||||
/// How "glossy" the surface is, where 0 is diffuse, and 1 is like a mirror.
|
||||
/// Multiplies with the alpha of the smoothness map if using one.
|
||||
/// </summary>
|
||||
[Range(0f, 1f)]
|
||||
[DefaultValue(0f)]
|
||||
public float smoothness = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// How metallic the surface is, from 0 to 1.
|
||||
/// Multiplies with the red of the smoothness map if using one.
|
||||
/// </summary>
|
||||
[Range(0f, 1f)]
|
||||
[DefaultValue(0f)]
|
||||
public float metallic = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for the normal (aka bump) map. Optional.
|
||||
/// </summary>
|
||||
public string normalMap;
|
||||
|
||||
/// <summary>
|
||||
/// Strength of the normal map. Usually 0-1, but can go above, or negative to invert the map.
|
||||
/// </summary>
|
||||
[DefaultValue(1f)]
|
||||
public float normalStrength = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for emission. Optional.
|
||||
/// </summary>
|
||||
@ -51,5 +84,79 @@ namespace NewHorizons.External.Modules
|
||||
/// Color multiplier of the emission texture. Defaults to white.
|
||||
/// </summary>
|
||||
public MColor emissionColor;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to the texture used for blending up to 5 tiles together, using the red, green, blue, and alpha channels, plus a lack of all 4 for a fifth "base" tile.
|
||||
/// Optional, even if using tiles (defaults to white, therefore either base or all other channels will be active).
|
||||
/// </summary>
|
||||
public string tileBlendMap;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. This tile will appear when all other tile channels are absent in the blend map, or when no other tiles are defined.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main textures control the general appearance, and make the tiles handle up close details.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo baseTile;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by red channel of the blend map.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo redTile;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by green channel of the blend map.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo greenTile;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by blue channel of the blend map.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo blueTile;
|
||||
|
||||
/// <summary>
|
||||
/// An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by alpha channel of the blend map.
|
||||
/// Note that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.
|
||||
/// </summary>
|
||||
public HeightMapTileInfo alphaTile;
|
||||
|
||||
[JsonObject]
|
||||
public class HeightMapTileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The size, in meters, of each tile.
|
||||
/// </summary>
|
||||
[Range(0f, double.MaxValue)]
|
||||
[DefaultValue(1f)]
|
||||
public float size = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to a color texture. Optional.
|
||||
/// Note that this tile texture will be multiplied with the main texture map. This means that white will multiply by 2, black by 0, and grey by 1.
|
||||
/// Thus, a texture that stays near (128, 128, 128) will blend nicely with the main texture map below.
|
||||
/// Colors other than greyscale can be used, but they might multiply strangely.
|
||||
/// </summary>
|
||||
public string textureTile;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to a texture for smoothness and metallic, which are controlled by the texture's alpha and red channels respectively. Optional.
|
||||
/// Note that this tile texture will be multiplied with the main smoothness map and/or values. This means that black/red will multiply by 2, transparent by 0, and half transparent by 1.
|
||||
/// Thus, a texture that stays near half alpha/red will blend nicely with the main smoothness map below.
|
||||
/// </summary>
|
||||
public string smoothnessTile;
|
||||
|
||||
/// <summary>
|
||||
/// Relative filepath to a normal (aka bump) texture. Optional.
|
||||
/// Blends additively with the main normal map.
|
||||
/// </summary>
|
||||
public string normalTile;
|
||||
|
||||
/// <summary>
|
||||
/// Strength of the tile normal. Usually 0-1, but can go above, or negative to invert the map.
|
||||
/// </summary>
|
||||
[DefaultValue(1f)]
|
||||
public float normalStrength = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,8 @@ namespace NewHorizons.External.Modules.Props.Audio
|
||||
public class AudioSourceInfo : BaseAudioInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio track of this audio source
|
||||
/// The audio track of this audio source.
|
||||
/// Most of the time you'll use environment (the default) for sound effects and music for music.
|
||||
/// </summary>
|
||||
[DefaultValue("environment")] public NHAudioMixerTrackName track = NHAudioMixerTrackName.Environment;
|
||||
}
|
||||
|
||||
@ -22,7 +22,10 @@ namespace NewHorizons.External.Modules.Props.Dialogue
|
||||
|
||||
/// <summary>
|
||||
/// If this dialogue is meant for a character, this is the relative path from the planet to that character's
|
||||
/// CharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking, or SolanumAnimController.
|
||||
/// CharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking,
|
||||
/// HearthianRecorderEffects or SolanumAnimController.
|
||||
///
|
||||
/// If it's a Recorder this will also delete the existing dialogue already attached to that prop.
|
||||
///
|
||||
/// If none of those components are present it will add a FacePlayerWhenTalking component.
|
||||
/// </summary>
|
||||
|
||||
@ -68,7 +68,7 @@ namespace NewHorizons.External.Modules.Props
|
||||
/// <summary>
|
||||
/// Fluid type for sounds/effects when colliding with this tornado.
|
||||
/// </summary>
|
||||
[DefaultValue("cloud")] public NHFluidType fluidType = NHFluidType.Cloud;
|
||||
[DefaultValue("cloud")] public NHFluidType fluidType = NHFluidType.CLOUD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace NewHorizons.External.Modules.TranslatorText
|
||||
@ -7,24 +8,34 @@ namespace NewHorizons.External.Modules.TranslatorText
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum NomaiTextType
|
||||
{
|
||||
[EnumMember(Value = @"wall")] Wall = 0,
|
||||
[EnumMember(Value = @"wall")] Wall,
|
||||
|
||||
[EnumMember(Value = @"scroll")] Scroll = 1,
|
||||
[EnumMember(Value = @"scroll")] Scroll,
|
||||
|
||||
[EnumMember(Value = @"computer")] Computer = 2,
|
||||
[EnumMember(Value = @"whiteboard")] Whiteboard,
|
||||
|
||||
[EnumMember(Value = @"cairn")] Cairn = 3,
|
||||
[EnumMember(Value = @"computer")] Computer,
|
||||
|
||||
[EnumMember(Value = @"recorder")] Recorder = 4,
|
||||
[EnumMember(Value = @"preCrashComputer")] PreCrashComputer,
|
||||
|
||||
[EnumMember(Value = @"preCrashRecorder")] PreCrashRecorder = 5,
|
||||
[EnumMember(Value = @"recorder")] Recorder,
|
||||
|
||||
[EnumMember(Value = @"preCrashComputer")] PreCrashComputer = 6,
|
||||
[EnumMember(Value = @"preCrashRecorder")] PreCrashRecorder,
|
||||
|
||||
[EnumMember(Value = @"trailmarker")] Trailmarker = 7,
|
||||
[EnumMember(Value = @"cairnBH")] CairnBrittleHollow,
|
||||
|
||||
[EnumMember(Value = @"cairnVariant")] CairnVariant = 8,
|
||||
[EnumMember(Value = @"cairnTH")] CairnTimberHearth,
|
||||
|
||||
[EnumMember(Value = @"whiteboard")] Whiteboard = 9,
|
||||
[EnumMember(Value = @"cairnCT")] CairnEmberTwin,
|
||||
|
||||
[EnumMember(Value = @"trailmarker")] Trailmarker,
|
||||
|
||||
#region Obsolete
|
||||
|
||||
[Obsolete("Please use CairnBrittleHollow instead")][EnumMember(Value = @"cairn")] Cairn,
|
||||
|
||||
[Obsolete("Please use CairnTimberHearth instead")][EnumMember(Value = @"cairnVariant")] CairnVariant,
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
2
NewHorizons/External/Modules/RingModule.cs
vendored
2
NewHorizons/External/Modules/RingModule.cs
vendored
@ -12,7 +12,7 @@ namespace NewHorizons.External.Modules
|
||||
/// <summary>
|
||||
/// Fluid type for sounds/effects when colliding with this ring.
|
||||
/// </summary>
|
||||
public NHFluidType fluidType = NHFluidType.None;
|
||||
public NHFluidType fluidType = NHFluidType.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// Angle between the rings and the equatorial plane of the planet.
|
||||
|
||||
@ -15,12 +15,12 @@ namespace NewHorizons.External.Modules.VariableSize
|
||||
/// <summary>
|
||||
/// Density of the water sphere. The higher the density, the harder it is to go through this fluid.
|
||||
/// </summary>
|
||||
[DefaultValue(1.2f)] public float density = 1.2f;
|
||||
[DefaultValue(30f)] public float density = 30f;
|
||||
|
||||
/// <summary>
|
||||
/// Buoyancy density of the water sphere
|
||||
/// </summary>
|
||||
[DefaultValue(1f)] public float buoyancy = 1f;
|
||||
[DefaultValue(1.1f)] public float buoyancy = 1.1f;
|
||||
|
||||
/// <summary>
|
||||
/// Tint of the water
|
||||
|
||||
@ -16,7 +16,8 @@ namespace NewHorizons.External.Modules.Volumes.VolumeInfos
|
||||
[DefaultValue("random")] public NHClipSelectionType clipSelection = NHClipSelectionType.RANDOM;
|
||||
|
||||
/// <summary>
|
||||
/// The audio track of this audio volume
|
||||
/// The audio track of this audio volume.
|
||||
/// Most of the time you'll use environment (the default) for sound effects and music for music.
|
||||
/// </summary>
|
||||
[DefaultValue("environment")] public NHAudioMixerTrackName track = NHAudioMixerTrackName.Environment;
|
||||
|
||||
|
||||
@ -8,12 +8,25 @@ namespace NewHorizons.External.Modules.Volumes.VolumeInfos
|
||||
{
|
||||
/// <summary>
|
||||
/// The layer of this volume.
|
||||
///
|
||||
/// Layers separate the priority system. The priority of volumes in one layer will not affect or override volumes in another. The highest priority volume in each layer will stack like normal.
|
||||
/// The exception is layer 0. A higher-priority volume in layer 0 will override lower-priority volumes in ALL other layers. A lower-priority volume in layer 0 will stack with other layers like normal.
|
||||
///
|
||||
/// Ex: A player could be affected by the sun on layer 9 priority 0 and planet gravity on layer 3 priority 2. They would experience the gravity of both volumes since they are on different layers.
|
||||
/// If there was a zero-g volume on layer 0 priority 1, since it is on layer 0 it will override the gravity from the sun (priority 0 which is less than 1) but they will still feel the
|
||||
/// gravity of the planet (priority 2 is greater than 1). The zero-g volume will also still be applied because it is on a different layer.
|
||||
///
|
||||
/// Default value here is 0 which means this volume's priority will be evaluated against all other priority volumes regardless of their layer.
|
||||
/// </summary>
|
||||
[DefaultValue(0)] public int layer = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The priority for this volume's effects to be applied.
|
||||
/// Ex, a player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.
|
||||
/// The priority of this volume.
|
||||
///
|
||||
/// Volumes of higher priority will override volumes of lower priority. Volumes of the same priority will stack like normal.
|
||||
/// Ex: A player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.
|
||||
///
|
||||
/// Default value here is 1 instead of 0 so it automatically overrides planet gravity, which is 0 by default.
|
||||
/// </summary>
|
||||
[DefaultValue(1)] public int priority = 1;
|
||||
}
|
||||
|
||||
@ -7,14 +7,14 @@ namespace NewHorizons.External.SerializableEnums
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum NHFluidType
|
||||
{
|
||||
[EnumMember(Value = @"none")] None = 0,
|
||||
|
||||
[EnumMember(Value = @"water")] Water = 1,
|
||||
|
||||
[EnumMember(Value = @"cloud")] Cloud = 2,
|
||||
|
||||
[EnumMember(Value = @"sand")] Sand = 3,
|
||||
|
||||
[EnumMember(Value = @"plasma")] Plasma = 4
|
||||
[EnumMember(Value = @"none")] NONE,
|
||||
[EnumMember(Value = @"air")] AIR,
|
||||
[EnumMember(Value = @"water")] WATER,
|
||||
[EnumMember(Value = @"tractorBeam")] TRACTOR_BEAM,
|
||||
[EnumMember(Value = @"cloud")] CLOUD,
|
||||
[EnumMember(Value = @"sand")] SAND,
|
||||
[EnumMember(Value = @"plasma")] PLASMA,
|
||||
[EnumMember(Value = @"fog")] FOG,
|
||||
[EnumMember(Value = @"geyser")] GEYSER
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ namespace NewHorizons.Handlers
|
||||
public class VesselCoordinatePromptHandler
|
||||
{
|
||||
private static List<Tuple<string, string, ScreenPrompt>> _factSystemIDPrompt;
|
||||
// TODO: move this to ImageUtilities
|
||||
private static List<Texture2D> _textureCache;
|
||||
|
||||
public static void RegisterPrompts(List<NewHorizonsSystem> systems)
|
||||
|
||||
@ -189,6 +189,8 @@ namespace NewHorizons
|
||||
{
|
||||
// Patches
|
||||
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly());
|
||||
// the campfire on the title screen calls this from RegisterShape before it gets patched, so we have to call it again. lol
|
||||
ShapeManager.Initialize();
|
||||
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
SceneManager.sceneUnloaded += OnSceneUnloaded;
|
||||
@ -196,8 +198,19 @@ namespace NewHorizons
|
||||
GlobalMessenger<DeathType>.AddListener("PlayerDeath", OnDeath);
|
||||
|
||||
GlobalMessenger.AddListener("WakeUp", OnWakeUp);
|
||||
|
||||
NHAssetBundle = ModHelper.Assets.LoadBundle("Assets/newhorizons_public");
|
||||
if (NHAssetBundle == null)
|
||||
{
|
||||
NHLogger.LogError("Couldn't find NHAssetBundle: The mod will likely not work.");
|
||||
}
|
||||
|
||||
NHPrivateAssetBundle = ModHelper.Assets.LoadBundle("Assets/newhorizons_private");
|
||||
if (NHPrivateAssetBundle == null)
|
||||
{
|
||||
NHLogger.LogError("Couldn't find NHPrivateAssetBundle: The mod will likely not work.");
|
||||
}
|
||||
|
||||
VesselWarpHandler.Initialize();
|
||||
|
||||
ResetConfigs(resetTranslation: false);
|
||||
@ -352,8 +365,15 @@ namespace NewHorizons
|
||||
IsChangingStarSystem = false;
|
||||
|
||||
if (isTitleScreen && _useCustomTitleScreen)
|
||||
{
|
||||
try
|
||||
{
|
||||
TitleSceneHandler.DisplayBodyOnTitleScreen(BodyDict.Values.ToList().SelectMany(x => x).ToList());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NHLogger.LogError($"Failed to make title screen bodies: {e}");
|
||||
}
|
||||
TitleSceneHandler.InitSubtitles();
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OWML" Version="2.9.0" />
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" />
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.456" />
|
||||
<Reference Include="../Lib/System.ComponentModel.Annotations.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace NewHorizons.Patches.DialoguePatches
|
||||
{
|
||||
[HarmonyPatch(typeof(HearthianRecorderEffects))]
|
||||
public static class HearthianRecorderEffectsPatches
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(HearthianRecorderEffects.Awake))]
|
||||
public static bool HearthianRecorderEffects_Awake(HearthianRecorderEffects __instance)
|
||||
{
|
||||
// If we're adding custom dialogue to a recorder the CharacterDialogueTree isn't going to be on the object
|
||||
if (__instance.GetComponent<CharacterDialogueTree>() == null)
|
||||
{
|
||||
__instance.enabled = false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
using HarmonyLib;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Patches.EchoesOfTheEyePatches
|
||||
{
|
||||
[HarmonyPatch(typeof(DreamWorldController))]
|
||||
public static class DreamworldControllerPatches
|
||||
{
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(nameof(DreamWorldController.FixedUpdate))]
|
||||
[HarmonyPatch(nameof(DreamWorldController.SpawnInDreamWorld))]
|
||||
public static IEnumerable<CodeInstruction> DreamWorldController_SpawnInDreamworld(IEnumerable<CodeInstruction> instructions)
|
||||
{
|
||||
// Thank you vio very cool!
|
||||
// For some reason in Patch 13 they made it so the planetary fog controller is disabled in the Dreamworld
|
||||
// This broke Hazy Dreams
|
||||
return new CodeMatcher(instructions).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(DreamWorldController), nameof(DreamWorldController._playerCamera))),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.Property(typeof(OWCamera), nameof(OWCamera.planetaryFog)).GetGetMethod()),
|
||||
new CodeMatch(OpCodes.Ldc_I4_0),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.Property(typeof(Behaviour), nameof(Behaviour.enabled)).GetSetMethod())
|
||||
)
|
||||
.Repeat(matcher => matcher.RemoveInstructions(5))
|
||||
.InstructionEnumeration();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,13 +12,13 @@ namespace NewHorizons.Patches
|
||||
{
|
||||
ShapeManager._exists = true;
|
||||
|
||||
ShapeManager._detectors = new ShapeManager.Layer(256);
|
||||
for (int index = 0; index < 256; ++index)
|
||||
ShapeManager._detectors = new ShapeManager.Layer(256 * 4);
|
||||
for (int index = 0; index < 256 * 4; ++index)
|
||||
ShapeManager._detectors[index].contacts = new List<ShapeManager.ContactData>(64);
|
||||
|
||||
ShapeManager._volumes = new ShapeManager.Layer[4];
|
||||
for (int index = 0; index < 4; ++index)
|
||||
ShapeManager._volumes[index] = new ShapeManager.Layer(2048);
|
||||
ShapeManager._volumes[index] = new ShapeManager.Layer(1024 * 2);
|
||||
|
||||
ShapeManager._locked = false;
|
||||
ShapeManager._frameFlag = false;
|
||||
|
||||
@ -73,11 +73,11 @@ namespace NewHorizons.Patches.ShipLogPatches
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(ShipLogManager.IsFactRevealed))]
|
||||
public static bool ShipLogManager_IsFactRevealed(ShipLogManager __instance, ref bool __result, string __0)
|
||||
public static bool ShipLogManager_IsFactRevealed(ShipLogManager __instance, ref bool __result, string id)
|
||||
{
|
||||
if (__instance._factDict != null && __instance._factDict.ContainsKey(__0))
|
||||
if (__instance._factDict != null && __instance._factDict.ContainsKey(id))
|
||||
{
|
||||
__result = __instance._factDict[__0].IsRevealed();
|
||||
__result = __instance._factDict[id].IsRevealed();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -129,10 +129,9 @@ namespace NewHorizons.Patches.ShipLogPatches
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(ShipLogManager.RevealFact))]
|
||||
public static void ShipLogManager_RevealFact(string __0)
|
||||
public static void ShipLogManager_RevealFact(string id)
|
||||
{
|
||||
StarChartHandler.OnRevealFact(__0);
|
||||
|
||||
StarChartHandler.OnRevealFact(id);
|
||||
AchievementHandler.OnRevealFact();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace NewHorizons.Patches.ShipLogPatches
|
||||
{
|
||||
[HarmonyPatch(typeof(SlideCollectionContainer))]
|
||||
public static class SlideCollectionContainerPatches
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(SlideCollectionContainer), nameof(SlideCollectionContainer.Initialize))]
|
||||
public static bool SlideCollectionContainer_Initialize(SlideCollectionContainer __instance)
|
||||
{
|
||||
if (__instance._initialized)
|
||||
return false;
|
||||
__instance.SetupReadFlags();
|
||||
__instance.RegisterPerSlideCompletion();
|
||||
if (__instance.streamingTexturesAvailable)
|
||||
__instance.SetupStreaming();
|
||||
__instance.BuildMusicRangesIndex();
|
||||
__instance._changeSlidesAllowed = true;
|
||||
__instance._initialized = true;
|
||||
__instance._slideCollection.isVision = __instance._owningItem == null;
|
||||
foreach (var factID in __instance._playWithShipLogFacts)
|
||||
{
|
||||
var fact = Locator.GetShipLogManager().GetFact(factID);
|
||||
fact?.RegisterSlideCollection(__instance._slideCollection);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,8 +81,8 @@ namespace NewHorizons.Patches.SignalPatches
|
||||
{
|
||||
if (!SignalBuilder.Initialized) return true;
|
||||
|
||||
var isCloaked = __instance._name.IsCloaked();
|
||||
var isOnQuantumMoon = __instance._name.IsOnQuantumMoon();
|
||||
var isCloaked = __instance.IsCloaked();
|
||||
var isOnQuantumMoon = __instance.IsOnQuantumMoon();
|
||||
|
||||
if (!isCloaked && !isOnQuantumMoon) return true;
|
||||
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace NewHorizons.Patches.ToolPatches
|
||||
{
|
||||
[HarmonyPatch(typeof(SurveyorProbe))]
|
||||
public static class SurveyorProbePatches
|
||||
{
|
||||
// This is to stop the game throwing too many errors if the probe is destroyed by a blackhole
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(SurveyorProbe.IsLaunched))]
|
||||
public static bool SurveyorProbe_IsLaunched(SurveyorProbe __instance, out bool __result)
|
||||
{
|
||||
__result = __instance?.gameObject?.activeSelf ?? false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -484,18 +484,26 @@
|
||||
"type": "string",
|
||||
"description": "",
|
||||
"x-enumNames": [
|
||||
"None",
|
||||
"Water",
|
||||
"Cloud",
|
||||
"Sand",
|
||||
"Plasma"
|
||||
"NONE",
|
||||
"AIR",
|
||||
"WATER",
|
||||
"TRACTOR_BEAM",
|
||||
"CLOUD",
|
||||
"SAND",
|
||||
"PLASMA",
|
||||
"FOG",
|
||||
"GEYSER"
|
||||
],
|
||||
"enum": [
|
||||
"none",
|
||||
"air",
|
||||
"water",
|
||||
"tractorBeam",
|
||||
"cloud",
|
||||
"sand",
|
||||
"plasma"
|
||||
"plasma",
|
||||
"fog",
|
||||
"geyser"
|
||||
]
|
||||
},
|
||||
"MGradient": {
|
||||
@ -560,7 +568,8 @@
|
||||
"gravityVolumePriority": {
|
||||
"type": "integer",
|
||||
"description": "Optional. You can force this planet's gravity to be felt over other gravity/zero-gravity sources by increasing this number.",
|
||||
"format": "int32"
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -841,10 +850,6 @@
|
||||
"description": "The scale of the terrain.",
|
||||
"$ref": "#/definitions/MVector3"
|
||||
},
|
||||
"textureMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for the terrain."
|
||||
},
|
||||
"resolution": {
|
||||
"type": "integer",
|
||||
"description": "Resolution of the heightmap.\nHigher values means more detail but also more memory/cpu/gpu usage.\nThis value will be 1:1 with the heightmap texture width, but only at the equator.",
|
||||
@ -853,6 +858,40 @@
|
||||
"maximum": 2000.0,
|
||||
"minimum": 4.0
|
||||
},
|
||||
"textureMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for the terrain colors."
|
||||
},
|
||||
"smoothnessMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for the terrain's smoothness and metallic, which are controlled by the texture's alpha and red channels respectively. Optional.\nTypically black with variable transparency, when metallic isn't wanted."
|
||||
},
|
||||
"smoothness": {
|
||||
"type": "number",
|
||||
"description": "How \"glossy\" the surface is, where 0 is diffuse, and 1 is like a mirror.\nMultiplies with the alpha of the smoothness map if using one.",
|
||||
"format": "float",
|
||||
"default": 0.0,
|
||||
"maximum": 1.0,
|
||||
"minimum": 0.0
|
||||
},
|
||||
"metallic": {
|
||||
"type": "number",
|
||||
"description": "How metallic the surface is, from 0 to 1.\nMultiplies with the red of the smoothness map if using one.",
|
||||
"format": "float",
|
||||
"default": 0.0,
|
||||
"maximum": 1.0,
|
||||
"minimum": 0.0
|
||||
},
|
||||
"normalMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for the normal (aka bump) map. Optional."
|
||||
},
|
||||
"normalStrength": {
|
||||
"type": "number",
|
||||
"description": "Strength of the normal map. Usually 0-1, but can go above, or negative to invert the map.",
|
||||
"format": "float",
|
||||
"default": 1.0
|
||||
},
|
||||
"emissionMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for emission. Optional."
|
||||
@ -860,6 +899,61 @@
|
||||
"emissionColor": {
|
||||
"description": "Color multiplier of the emission texture. Defaults to white.",
|
||||
"$ref": "#/definitions/MColor"
|
||||
},
|
||||
"tileBlendMap": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to the texture used for blending up to 5 tiles together, using the red, green, blue, and alpha channels, plus a lack of all 4 for a fifth \"base\" tile.\nOptional, even if using tiles (defaults to white, therefore either base or all other channels will be active)."
|
||||
},
|
||||
"baseTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. This tile will appear when all other tile channels are absent in the blend map, or when no other tiles are defined.\nNote that tiles will not be active from afar, so it is recommended to make the main textures control the general appearance, and make the tiles handle up close details.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
},
|
||||
"redTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by red channel of the blend map.\nNote that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
},
|
||||
"greenTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by green channel of the blend map.\nNote that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
},
|
||||
"blueTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by blue channel of the blend map.\nNote that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
},
|
||||
"alphaTile": {
|
||||
"description": "An optional set of textures that can tile and combine with the main maps. The distribution of this tile is controlled by alpha channel of the blend map.\nNote that tiles will not be active from afar, so it is recommended to make the main maps control the general appearance more than the tiles.",
|
||||
"$ref": "#/definitions/HeightMapTileInfo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HeightMapTileInfo": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"size": {
|
||||
"type": "number",
|
||||
"description": "The size, in meters, of each tile.",
|
||||
"format": "float",
|
||||
"default": 1.0,
|
||||
"minimum": 0.0
|
||||
},
|
||||
"textureTile": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to a color texture. Optional.\nNote that this tile texture will be multiplied with the main texture map. This means that white will multiply by 2, black by 0, and grey by 1.\nThus, a texture that stays near (128, 128, 128) will blend nicely with the main texture map below.\nColors other than greyscale can be used, but they might multiply strangely."
|
||||
},
|
||||
"smoothnessTile": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to a texture for smoothness and metallic, which are controlled by the texture's alpha and red channels respectively. Optional.\nNote that this tile texture will be multiplied with the main smoothness map and/or values. This means that black/red will multiply by 2, transparent by 0, and half transparent by 1.\nThus, a texture that stays near half alpha/red will blend nicely with the main smoothness map below."
|
||||
},
|
||||
"normalTile": {
|
||||
"type": "string",
|
||||
"description": "Relative filepath to a normal (aka bump) texture. Optional.\nBlends additively with the main normal map."
|
||||
},
|
||||
"normalStrength": {
|
||||
"type": "number",
|
||||
"description": "Strength of the tile normal. Usually 0-1, but can go above, or negative to invert the map.",
|
||||
"format": "float",
|
||||
"default": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1229,7 +1323,7 @@
|
||||
},
|
||||
"pathToAnimController": {
|
||||
"type": "string",
|
||||
"description": "If this dialogue is meant for a character, this is the relative path from the planet to that character's\nCharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking, or SolanumAnimController.\n\nIf none of those components are present it will add a FacePlayerWhenTalking component."
|
||||
"description": "If this dialogue is meant for a character, this is the relative path from the planet to that character's\nCharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking, \nHearthianRecorderEffects or SolanumAnimController.\n\nIf it's a Recorder this will also delete the existing dialogue already attached to that prop.\n\nIf none of those components are present it will add a FacePlayerWhenTalking component."
|
||||
},
|
||||
"radius": {
|
||||
"type": "number",
|
||||
@ -1542,26 +1636,28 @@
|
||||
"x-enumNames": [
|
||||
"Wall",
|
||||
"Scroll",
|
||||
"Whiteboard",
|
||||
"Computer",
|
||||
"Cairn",
|
||||
"PreCrashComputer",
|
||||
"Recorder",
|
||||
"PreCrashRecorder",
|
||||
"PreCrashComputer",
|
||||
"Trailmarker",
|
||||
"CairnVariant",
|
||||
"Whiteboard"
|
||||
"CairnBrittleHollow",
|
||||
"CairnTimberHearth",
|
||||
"CairnEmberTwin",
|
||||
"Trailmarker"
|
||||
],
|
||||
"enum": [
|
||||
"wall",
|
||||
"scroll",
|
||||
"whiteboard",
|
||||
"computer",
|
||||
"cairn",
|
||||
"preCrashComputer",
|
||||
"recorder",
|
||||
"preCrashRecorder",
|
||||
"preCrashComputer",
|
||||
"trailmarker",
|
||||
"cairnVariant",
|
||||
"whiteboard"
|
||||
"cairnBH",
|
||||
"cairnTH",
|
||||
"cairnCT",
|
||||
"trailmarker"
|
||||
]
|
||||
},
|
||||
"NomaiTextLocation": {
|
||||
@ -2604,7 +2700,7 @@
|
||||
"description": "An optional rename of this object"
|
||||
},
|
||||
"track": {
|
||||
"description": "The audio track of this audio source",
|
||||
"description": "The audio track of this audio source.\nMost of the time you'll use environment (the default) for sound effects and music for music. ",
|
||||
"default": "environment",
|
||||
"$ref": "#/definitions/NHAudioMixerTrackName"
|
||||
}
|
||||
@ -3140,13 +3236,13 @@
|
||||
"type": "number",
|
||||
"description": "Density of the water sphere. The higher the density, the harder it is to go through this fluid.",
|
||||
"format": "float",
|
||||
"default": 1.2
|
||||
"default": 30.0
|
||||
},
|
||||
"buoyancy": {
|
||||
"type": "number",
|
||||
"description": "Buoyancy density of the water sphere",
|
||||
"format": "float",
|
||||
"default": 1.0
|
||||
"default": 1.1
|
||||
},
|
||||
"tint": {
|
||||
"description": "Tint of the water",
|
||||
@ -3297,13 +3393,13 @@
|
||||
"properties": {
|
||||
"layer": {
|
||||
"type": "integer",
|
||||
"description": "The layer of this volume.",
|
||||
"description": "The layer of this volume.\n\nLayers separate the priority system. The priority of volumes in one layer will not affect or override volumes in another. The highest priority volume in each layer will stack like normal.\nThe exception is layer 0. A higher-priority volume in layer 0 will override lower-priority volumes in ALL other layers. A lower-priority volume in layer 0 will stack with other layers like normal.\n \nEx: A player could be affected by the sun on layer 9 priority 0 and planet gravity on layer 3 priority 2. They would experience the gravity of both volumes since they are on different layers.\nIf there was a zero-g volume on layer 0 priority 1, since it is on layer 0 it will override the gravity from the sun (priority 0 which is less than 1) but they will still feel the \ngravity of the planet (priority 2 is greater than 1). The zero-g volume will also still be applied because it is on a different layer.\n \nDefault value here is 0 which means this volume's priority will be evaluated against all other priority volumes regardless of their layer.",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer",
|
||||
"description": "The priority for this volume's effects to be applied. \nEx, a player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.",
|
||||
"description": "The priority of this volume.\n\nVolumes of higher priority will override volumes of lower priority. Volumes of the same priority will stack like normal.\nEx: A player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.\n \nDefault value here is 1 instead of 0 so it automatically overrides planet gravity, which is 0 by default. ",
|
||||
"format": "int32",
|
||||
"default": 1
|
||||
},
|
||||
@ -3338,7 +3434,7 @@
|
||||
"$ref": "#/definitions/NHClipSelectionType"
|
||||
},
|
||||
"track": {
|
||||
"description": "The audio track of this audio volume",
|
||||
"description": "The audio track of this audio volume.\nMost of the time you'll use environment (the default) for sound effects and music for music. ",
|
||||
"default": "environment",
|
||||
"$ref": "#/definitions/NHAudioMixerTrackName"
|
||||
},
|
||||
@ -3475,13 +3571,13 @@
|
||||
"properties": {
|
||||
"layer": {
|
||||
"type": "integer",
|
||||
"description": "The layer of this volume.",
|
||||
"description": "The layer of this volume.\n\nLayers separate the priority system. The priority of volumes in one layer will not affect or override volumes in another. The highest priority volume in each layer will stack like normal.\nThe exception is layer 0. A higher-priority volume in layer 0 will override lower-priority volumes in ALL other layers. A lower-priority volume in layer 0 will stack with other layers like normal.\n \nEx: A player could be affected by the sun on layer 9 priority 0 and planet gravity on layer 3 priority 2. They would experience the gravity of both volumes since they are on different layers.\nIf there was a zero-g volume on layer 0 priority 1, since it is on layer 0 it will override the gravity from the sun (priority 0 which is less than 1) but they will still feel the \ngravity of the planet (priority 2 is greater than 1). The zero-g volume will also still be applied because it is on a different layer.\n \nDefault value here is 0 which means this volume's priority will be evaluated against all other priority volumes regardless of their layer.",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer",
|
||||
"description": "The priority for this volume's effects to be applied. \nEx, a player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.",
|
||||
"description": "The priority of this volume.\n\nVolumes of higher priority will override volumes of lower priority. Volumes of the same priority will stack like normal.\nEx: A player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.\n \nDefault value here is 1 instead of 0 so it automatically overrides planet gravity, which is 0 by default. ",
|
||||
"format": "int32",
|
||||
"default": 1
|
||||
},
|
||||
@ -4100,13 +4196,13 @@
|
||||
"properties": {
|
||||
"layer": {
|
||||
"type": "integer",
|
||||
"description": "The layer of this volume.",
|
||||
"description": "The layer of this volume.\n\nLayers separate the priority system. The priority of volumes in one layer will not affect or override volumes in another. The highest priority volume in each layer will stack like normal.\nThe exception is layer 0. A higher-priority volume in layer 0 will override lower-priority volumes in ALL other layers. A lower-priority volume in layer 0 will stack with other layers like normal.\n \nEx: A player could be affected by the sun on layer 9 priority 0 and planet gravity on layer 3 priority 2. They would experience the gravity of both volumes since they are on different layers.\nIf there was a zero-g volume on layer 0 priority 1, since it is on layer 0 it will override the gravity from the sun (priority 0 which is less than 1) but they will still feel the \ngravity of the planet (priority 2 is greater than 1). The zero-g volume will also still be applied because it is on a different layer.\n \nDefault value here is 0 which means this volume's priority will be evaluated against all other priority volumes regardless of their layer.",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer",
|
||||
"description": "The priority for this volume's effects to be applied. \nEx, a player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.",
|
||||
"description": "The priority of this volume.\n\nVolumes of higher priority will override volumes of lower priority. Volumes of the same priority will stack like normal.\nEx: A player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.\n \nDefault value here is 1 instead of 0 so it automatically overrides planet gravity, which is 0 by default. ",
|
||||
"format": "int32",
|
||||
"default": 1
|
||||
},
|
||||
@ -4154,13 +4250,13 @@
|
||||
"properties": {
|
||||
"layer": {
|
||||
"type": "integer",
|
||||
"description": "The layer of this volume.",
|
||||
"description": "The layer of this volume.\n\nLayers separate the priority system. The priority of volumes in one layer will not affect or override volumes in another. The highest priority volume in each layer will stack like normal.\nThe exception is layer 0. A higher-priority volume in layer 0 will override lower-priority volumes in ALL other layers. A lower-priority volume in layer 0 will stack with other layers like normal.\n \nEx: A player could be affected by the sun on layer 9 priority 0 and planet gravity on layer 3 priority 2. They would experience the gravity of both volumes since they are on different layers.\nIf there was a zero-g volume on layer 0 priority 1, since it is on layer 0 it will override the gravity from the sun (priority 0 which is less than 1) but they will still feel the \ngravity of the planet (priority 2 is greater than 1). The zero-g volume will also still be applied because it is on a different layer.\n \nDefault value here is 0 which means this volume's priority will be evaluated against all other priority volumes regardless of their layer.",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer",
|
||||
"description": "The priority for this volume's effects to be applied. \nEx, a player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.",
|
||||
"description": "The priority of this volume.\n\nVolumes of higher priority will override volumes of lower priority. Volumes of the same priority will stack like normal.\nEx: A player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.\n \nDefault value here is 1 instead of 0 so it automatically overrides planet gravity, which is 0 by default. ",
|
||||
"format": "int32",
|
||||
"default": 1
|
||||
},
|
||||
@ -4228,13 +4324,13 @@
|
||||
},
|
||||
"layer": {
|
||||
"type": "integer",
|
||||
"description": "The layer of this volume.",
|
||||
"description": "The layer of this volume.\n\nLayers separate the priority system. The priority of volumes in one layer will not affect or override volumes in another. The highest priority volume in each layer will stack like normal.\nThe exception is layer 0. A higher-priority volume in layer 0 will override lower-priority volumes in ALL other layers. A lower-priority volume in layer 0 will stack with other layers like normal.\n \nEx: A player could be affected by the sun on layer 9 priority 0 and planet gravity on layer 3 priority 2. They would experience the gravity of both volumes since they are on different layers.\nIf there was a zero-g volume on layer 0 priority 1, since it is on layer 0 it will override the gravity from the sun (priority 0 which is less than 1) but they will still feel the \ngravity of the planet (priority 2 is greater than 1). The zero-g volume will also still be applied because it is on a different layer.\n \nDefault value here is 0 which means this volume's priority will be evaluated against all other priority volumes regardless of their layer.",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
},
|
||||
"priority": {
|
||||
"type": "integer",
|
||||
"description": "The priority for this volume's effects to be applied. \nEx, a player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.",
|
||||
"description": "The priority of this volume.\n\nVolumes of higher priority will override volumes of lower priority. Volumes of the same priority will stack like normal.\nEx: A player in a gravity volume with priority 0, and zero-gravity volume with priority 1, will feel zero gravity.\n \nDefault value here is 1 instead of 0 so it automatically overrides planet gravity, which is 0 by default. ",
|
||||
"format": "int32",
|
||||
"default": 1
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using HarmonyLib;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
using System;
|
||||
@ -13,40 +14,43 @@ namespace NewHorizons.Utility.Files
|
||||
{
|
||||
public static class ImageUtilities
|
||||
{
|
||||
private static readonly Dictionary<string, Texture2D> _loadedTextures = new();
|
||||
private static readonly List<Texture> _generatedTextures = new();
|
||||
// key is path + applied effects
|
||||
private static readonly Dictionary<string, Texture> _textureCache = new();
|
||||
public static bool CheckCachedTexture(string key, out Texture existingTexture) => _textureCache.TryGetValue(key, out existingTexture);
|
||||
public static void TrackCachedTexture(string key, Texture texture) => _textureCache.Add(key, texture);
|
||||
|
||||
/// <summary>
|
||||
/// Track textures generated outside of this file so they can be cleaned up on scene unload
|
||||
/// </summary>
|
||||
/// <param name="texture"></param>
|
||||
public static void TrackGeneratedTexture(Texture texture) => _generatedTextures.Add(texture);
|
||||
private static string GetKey(string path) => path.Substring(Main.Instance.ModHelper.OwmlConfig.ModsPath.Length);
|
||||
|
||||
public static bool IsTextureLoaded(IModBehaviour mod, string filename)
|
||||
{
|
||||
var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, filename);
|
||||
return _loadedTextures.ContainsKey(path);
|
||||
var key = GetKey(path);
|
||||
return _textureCache.ContainsKey(key);
|
||||
}
|
||||
|
||||
public static Texture2D GetTexture(IModBehaviour mod, string filename, bool useMipmaps = true, bool wrap = false)
|
||||
// needed for backwards compat :P
|
||||
public static Texture2D GetTexture(IModBehaviour mod, string filename, bool useMipmaps, bool wrap) => GetTexture(mod, filename, useMipmaps, wrap, false);
|
||||
// bug: cache only considers file path, not wrap/mips/linear. oh well
|
||||
public static Texture2D GetTexture(IModBehaviour mod, string filename, bool useMipmaps = true, bool wrap = false, bool linear = false)
|
||||
{
|
||||
// Copied from OWML but without the print statement lol
|
||||
var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, filename);
|
||||
if (_loadedTextures.ContainsKey(path))
|
||||
var key = GetKey(path);
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture))
|
||||
{
|
||||
NHLogger.LogVerbose($"Already loaded image at path: {path}");
|
||||
return _loadedTextures[path];
|
||||
return (Texture2D)existingTexture;
|
||||
}
|
||||
|
||||
NHLogger.LogVerbose($"Loading image at path: {path}");
|
||||
try
|
||||
{
|
||||
var data = File.ReadAllBytes(path);
|
||||
var texture = new Texture2D(2, 2, TextureFormat.RGBA32, useMipmaps);
|
||||
texture.name = Path.GetFileNameWithoutExtension(path);
|
||||
var texture = new Texture2D(2, 2, TextureFormat.RGBA32, useMipmaps, linear);
|
||||
texture.name = key;
|
||||
texture.wrapMode = wrap ? TextureWrapMode.Repeat : TextureWrapMode.Clamp;
|
||||
texture.LoadImage(data);
|
||||
_loadedTextures.Add(path, texture);
|
||||
_textureCache.Add(key, texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
@ -61,11 +65,12 @@ namespace NewHorizons.Utility.Files
|
||||
public static void DeleteTexture(IModBehaviour mod, string filename, Texture2D texture)
|
||||
{
|
||||
var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, filename);
|
||||
if (_loadedTextures.ContainsKey(path))
|
||||
var key = GetKey(path);
|
||||
if (_textureCache.ContainsKey(key))
|
||||
{
|
||||
if (_loadedTextures[path] == texture)
|
||||
if (_textureCache[key] == texture)
|
||||
{
|
||||
_loadedTextures.Remove(path);
|
||||
_textureCache.Remove(key);
|
||||
UnityEngine.Object.Destroy(texture);
|
||||
}
|
||||
}
|
||||
@ -77,23 +82,19 @@ namespace NewHorizons.Utility.Files
|
||||
{
|
||||
NHLogger.LogVerbose("Clearing image cache");
|
||||
|
||||
foreach (var texture in _loadedTextures.Values)
|
||||
foreach (var texture in _textureCache.Values)
|
||||
{
|
||||
if (texture == null) continue;
|
||||
UnityEngine.Object.Destroy(texture);
|
||||
}
|
||||
_loadedTextures.Clear();
|
||||
|
||||
foreach (var texture in _generatedTextures)
|
||||
{
|
||||
if (texture == null) continue;
|
||||
UnityEngine.Object.Destroy(texture);
|
||||
}
|
||||
_generatedTextures.Clear();
|
||||
_textureCache.Clear();
|
||||
}
|
||||
|
||||
public static Texture2D Invert(Texture2D texture)
|
||||
{
|
||||
var key = $"{texture.name} > invert";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
|
||||
var pixels = texture.GetPixels();
|
||||
for (int i = 0; i < pixels.Length; i++)
|
||||
{
|
||||
@ -117,23 +118,26 @@ namespace NewHorizons.Utility.Files
|
||||
}
|
||||
|
||||
var newTexture = new Texture2D(texture.width, texture.height, texture.format, texture.mipmapCount != 1);
|
||||
newTexture.name = texture.name + "Inverted";
|
||||
newTexture.name = key;
|
||||
newTexture.SetPixels(pixels);
|
||||
newTexture.Apply();
|
||||
|
||||
newTexture.wrapMode = texture.wrapMode;
|
||||
|
||||
_generatedTextures.Add(newTexture);
|
||||
_textureCache.Add(key, newTexture);
|
||||
|
||||
return newTexture;
|
||||
}
|
||||
|
||||
public static Texture2D MakeReelTexture(Texture2D[] textures)
|
||||
{
|
||||
var key = $"SlideReelAtlas of {textures.Join(x => x.name)}";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
|
||||
var size = 256;
|
||||
|
||||
var texture = new Texture2D(size * 4, size * 4, TextureFormat.ARGB32, false);
|
||||
texture.name = "SlideReelAtlas";
|
||||
texture.name = key;
|
||||
|
||||
var fillPixels = new Color[size * size * 4 * 4];
|
||||
for (int xIndex = 0; xIndex < 4; xIndex++)
|
||||
@ -175,15 +179,18 @@ namespace NewHorizons.Utility.Files
|
||||
texture.SetPixels(fillPixels);
|
||||
texture.Apply();
|
||||
|
||||
_generatedTextures.Add(texture);
|
||||
_textureCache.Add(key, texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
public static Texture2D MakeOutline(Texture2D texture, Color color, int thickness)
|
||||
{
|
||||
var key = $"{texture.name} > outline {color} {thickness}";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
|
||||
var outline = new Texture2D(texture.width, texture.height, texture.format, texture.mipmapCount != 1);
|
||||
outline.name = texture.name + "Outline";
|
||||
outline.name = key;
|
||||
var outlinePixels = new Color[texture.width * texture.height];
|
||||
var pixels = texture.GetPixels();
|
||||
|
||||
@ -206,7 +213,7 @@ namespace NewHorizons.Utility.Files
|
||||
|
||||
outline.wrapMode = texture.wrapMode;
|
||||
|
||||
_generatedTextures.Add(outline);
|
||||
_textureCache.Add(key, outline);
|
||||
|
||||
return outline;
|
||||
}
|
||||
@ -231,6 +238,9 @@ namespace NewHorizons.Utility.Files
|
||||
|
||||
public static Texture2D TintImage(Texture2D image, Color tint)
|
||||
{
|
||||
var key = $"{image.name} > tint {tint}";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
NHLogger.LogError($"Tried to tint null image");
|
||||
@ -246,19 +256,22 @@ namespace NewHorizons.Utility.Files
|
||||
}
|
||||
|
||||
var newImage = new Texture2D(image.width, image.height, image.format, image.mipmapCount != 1);
|
||||
newImage.name = image.name + "Tinted";
|
||||
newImage.name = key;
|
||||
newImage.SetPixels(pixels);
|
||||
newImage.Apply();
|
||||
|
||||
newImage.wrapMode = image.wrapMode;
|
||||
|
||||
_generatedTextures.Add(newImage);
|
||||
_textureCache.Add(key, newImage);
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
public static Texture2D LerpGreyscaleImage(Texture2D image, Color lightTint, Color darkTint)
|
||||
{
|
||||
var key = $"{image.name} > lerp greyscale {lightTint} {darkTint}";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
|
||||
var pixels = image.GetPixels();
|
||||
for (int i = 0; i < pixels.Length; i++)
|
||||
{
|
||||
@ -268,21 +281,24 @@ namespace NewHorizons.Utility.Files
|
||||
}
|
||||
|
||||
var newImage = new Texture2D(image.width, image.height, image.format, image.mipmapCount != 1);
|
||||
newImage.name = image.name + "LerpedGrayscale";
|
||||
newImage.name = key;
|
||||
newImage.SetPixels(pixels);
|
||||
newImage.Apply();
|
||||
|
||||
newImage.wrapMode = image.wrapMode;
|
||||
|
||||
_generatedTextures.Add(newImage);
|
||||
_textureCache.Add(key, newImage);
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
public static Texture2D ClearTexture(int width, int height, bool wrap = false)
|
||||
{
|
||||
var key = $"Clear {width} {height} {wrap}";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
|
||||
var tex = new Texture2D(1, 1, TextureFormat.ARGB32, false);
|
||||
tex.name = "Clear";
|
||||
tex.name = key;
|
||||
var fillColor = Color.clear;
|
||||
var fillPixels = new Color[tex.width * tex.height];
|
||||
for (int i = 0; i < fillPixels.Length; i++)
|
||||
@ -294,15 +310,18 @@ namespace NewHorizons.Utility.Files
|
||||
|
||||
tex.wrapMode = wrap ? TextureWrapMode.Repeat : TextureWrapMode.Clamp;
|
||||
|
||||
_generatedTextures.Add(tex);
|
||||
_textureCache.Add(key, tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
public static Texture2D CanvasScaled(Texture2D src, int width, int height)
|
||||
{
|
||||
var key = $"{src.name} > canvas scaled {width} {height}";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
|
||||
var tex = new Texture2D(width, height, src.format, src.mipmapCount != 1);
|
||||
tex.name = src.name + "CanvasScaled";
|
||||
tex.name = key;
|
||||
var fillPixels = new Color[tex.width * tex.height];
|
||||
for (int i = 0; i < tex.width; i++)
|
||||
{
|
||||
@ -322,7 +341,7 @@ namespace NewHorizons.Utility.Files
|
||||
|
||||
tex.wrapMode = src.wrapMode;
|
||||
|
||||
_generatedTextures.Add(tex);
|
||||
_textureCache.Add(key, tex);
|
||||
|
||||
return tex;
|
||||
}
|
||||
@ -410,13 +429,13 @@ namespace NewHorizons.Utility.Files
|
||||
|
||||
IEnumerator DownloadTexture(string url, int index)
|
||||
{
|
||||
lock (_loadedTextures)
|
||||
var key = GetKey(url);
|
||||
lock (_textureCache)
|
||||
{
|
||||
if (_loadedTextures.ContainsKey(url))
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture))
|
||||
{
|
||||
NHLogger.LogVerbose($"Already loaded image {index}:{url}");
|
||||
var texture = _loadedTextures[url];
|
||||
imageLoadedEvent?.Invoke(texture, index);
|
||||
imageLoadedEvent?.Invoke((Texture2D)existingTexture, index);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
@ -433,25 +452,24 @@ namespace NewHorizons.Utility.Files
|
||||
}
|
||||
else
|
||||
{
|
||||
var texture = new Texture2D(2, 2, TextureFormat.RGBA32, false)
|
||||
{
|
||||
wrapMode = TextureWrapMode.Clamp
|
||||
};
|
||||
var texture = new Texture2D(2, 2, TextureFormat.RGBA32, false);
|
||||
texture.name = key;
|
||||
texture.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
var handler = (DownloadHandlerTexture)uwr.downloadHandler;
|
||||
texture.LoadImage(handler.data);
|
||||
|
||||
lock (_loadedTextures)
|
||||
lock (_textureCache)
|
||||
{
|
||||
if (_loadedTextures.ContainsKey(url))
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture))
|
||||
{
|
||||
NHLogger.LogVerbose($"Already loaded image {index}:{url}");
|
||||
Destroy(texture);
|
||||
texture = _loadedTextures[url];
|
||||
texture = (Texture2D)existingTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
_loadedTextures.Add(url, texture);
|
||||
_textureCache.Add(key, texture);
|
||||
}
|
||||
|
||||
imageLoadedEvent?.Invoke(texture, index);
|
||||
|
||||
@ -5,22 +5,23 @@ namespace NewHorizons.Utility.Geometry
|
||||
{
|
||||
// Longitude and latitude are in degrees
|
||||
// Using the phi and theta convention used on https://mathworld.wolfram.com/SphericalCoordinates.html (Mathematics not physics convention)
|
||||
public static Vector3 CartesianToSpherical(Vector3 v, bool useUnityCoords = true)
|
||||
public static Vector3 CartesianToSpherical(Vector3 v, bool useShaderCoords = false)
|
||||
{
|
||||
float x, y, z;
|
||||
if (useUnityCoords)
|
||||
if (useShaderCoords)
|
||||
{
|
||||
// Y is DOWN in the shader
|
||||
x = v.x;
|
||||
y = v.z;
|
||||
z = -v.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Y is up in unity
|
||||
x = v.x;
|
||||
y = v.z;
|
||||
z = v.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
float dist = Mathf.Sqrt(x * x + y * y + z * z);
|
||||
|
||||
@ -33,7 +34,7 @@ namespace NewHorizons.Utility.Geometry
|
||||
return new Vector3(longitude, latitude, dist);
|
||||
}
|
||||
|
||||
public static Vector3 SphericalToCartesian(Vector3 v, bool useUnityCoords = true)
|
||||
public static Vector3 SphericalToCartesian(Vector3 v)
|
||||
{
|
||||
var longitude = v.x;
|
||||
var latitude = v.y;
|
||||
@ -44,18 +45,9 @@ namespace NewHorizons.Utility.Geometry
|
||||
|
||||
float x, y, z;
|
||||
|
||||
if (useUnityCoords)
|
||||
{
|
||||
x = r * Mathf.Cos(theta) * Mathf.Sin(phi);
|
||||
z = r * Mathf.Sin(theta) * Mathf.Sin(phi);
|
||||
y = r * Mathf.Cos(phi);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = r * Mathf.Cos(theta) * Mathf.Sin(phi);
|
||||
y = r * Mathf.Sin(theta) * Mathf.Sin(phi);
|
||||
z = r * Mathf.Cos(phi);
|
||||
}
|
||||
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
@ -255,13 +255,13 @@ namespace NewHorizons.Utility
|
||||
}
|
||||
|
||||
public static FluidVolume.Type ConvertToOW(this NHFluidType fluidType, FluidVolume.Type @default = FluidVolume.Type.NONE)
|
||||
=> EnumUtils.Parse(fluidType.ToString().ToUpper(), @default);
|
||||
=> EnumUtils.Parse(fluidType.ToString(), @default);
|
||||
|
||||
public static OWAudioMixer.TrackName ConvertToOW(this NHAudioMixerTrackName trackName, OWAudioMixer.TrackName @default = OWAudioMixer.TrackName.Environment)
|
||||
=> EnumUtils.Parse(trackName.ToString().ToUpper(), @default);
|
||||
=> EnumUtils.Parse(trackName.ToString(), @default);
|
||||
|
||||
public static OWAudioSource.ClipSelectionOnPlay ConvertToOW(this NHClipSelectionType clipSelection, OWAudioSource.ClipSelectionOnPlay @default = OWAudioSource.ClipSelectionOnPlay.RANDOM)
|
||||
=> EnumUtils.Parse(clipSelection.ToString().ToUpper(), @default);
|
||||
=> EnumUtils.Parse(clipSelection.ToString(), @default);
|
||||
|
||||
public static void SmoothLookDir(this GameObject go, Vector3 direction, float dt, float angularVelocity)
|
||||
{
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book",
|
||||
"name": "New Horizons",
|
||||
"uniqueName": "xen.NewHorizons",
|
||||
"version": "1.10.2",
|
||||
"version": "1.12.1",
|
||||
"owmlVersion": "2.9.0",
|
||||
"dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ],
|
||||
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],
|
||||
|
||||
@ -82,6 +82,10 @@ public static class SchemaExporter
|
||||
{
|
||||
case "Celestial Body Schema":
|
||||
schema.Definitions["OrbitModule"].Properties["semiMajorAxis"].Default = 5000f;
|
||||
schema.Definitions["NomaiTextType"].Enumeration.Remove("cairn");
|
||||
schema.Definitions["NomaiTextType"].EnumerationNames.Remove("Cairn");
|
||||
schema.Definitions["NomaiTextType"].Enumeration.Remove("cairnVariant");
|
||||
schema.Definitions["NomaiTextType"].EnumerationNames.Remove("CairnVariant");
|
||||
break;
|
||||
case "Star System Schema":
|
||||
schema.Definitions["NomaiCoordinates"].Properties["x"].UniqueItems = true;
|
||||
|
||||
@ -18,9 +18,9 @@
|
||||
<None Include="UnityEngine.CoreModule.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="NJsonSchema" Version="10.8.0" />
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" IncludeAssets="compile" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NJsonSchema" Version="10.9.0" />
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.456" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"base": "styles/nh_base.css"
|
||||
},
|
||||
"search": {
|
||||
"enabled": true,
|
||||
"enabled": false,
|
||||
"site": "nh.outerwildsmods.com"
|
||||
},
|
||||
"brand": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user