Merge branch 'dev' into slide-threading

This commit is contained in:
Nick 2022-09-13 20:14:37 -04:00 committed by GitHub
commit b86e5454cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 111 additions and 106 deletions

View File

@ -2,9 +2,11 @@ using NewHorizons.External.Modules;
using NewHorizons.Handlers; using NewHorizons.Handlers;
using NewHorizons.Utility; using NewHorizons.Utility;
using OWML.Common; using OWML.Common;
using OWML.Common.Menus;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.IO;
using UnityEngine; using UnityEngine;
using Logger = NewHorizons.Utility.Logger; using Logger = NewHorizons.Utility.Logger;
namespace NewHorizons.Builder.Props namespace NewHorizons.Builder.Props
@ -89,19 +91,8 @@ namespace NewHorizons.Builder.Props
// The base game ones only have 15 slides max // The base game ones only have 15 slides max
var textures = new Texture2D[slidesCount >= 15 ? 15 : slidesCount]; var textures = new Texture2D[slidesCount >= 15 ? 15 : slidesCount];
var imageLoader = slideReelObj.AddComponent<ImageUtilities.AsyncImageLoader>(); var imageLoader = AddAsyncLoader(slideReelObj, mod, info.slides, ref slideCollection);
for (int i = 0; i < slidesCount; i++)
{
var slide = new Slide();
var slideInfo = info.slides[i];
imageLoader.pathsToLoad.Add(mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath);
AddModules(slideInfo, ref slide, mod);
slideCollection.slides[i] = slide;
}
// this variable just lets us track how many of the first 15 slides have been loaded. // this variable just lets us track how many of the first 15 slides have been loaded.
// this way as soon as the last one is loaded (due to async loading, this may be // this way as soon as the last one is loaded (due to async loading, this may be
// slide 7, or slide 3, or whatever), we can build the slide reel texture. This allows us // slide 7, or slide 3, or whatever), we can build the slide reel texture. This allows us
@ -189,18 +180,7 @@ namespace NewHorizons.Builder.Props
int slidesCount = info.slides.Length; int slidesCount = info.slides.Length;
var slideCollection = new SlideCollection(slidesCount); var slideCollection = new SlideCollection(slidesCount);
var imageLoader = projectorObj.AddComponent<ImageUtilities.AsyncImageLoader>(); var imageLoader = AddAsyncLoader(projectorObj, mod, info.slides, ref slideCollection);
for (int i = 0; i < slidesCount; i++)
{
var slide = new Slide();
var slideInfo = info.slides[i];
imageLoader.pathsToLoad.Add(mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath);
AddModules(slideInfo, ref slide, mod);
slideCollection.slides[i] = slide;
}
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = ImageUtilities.Invert(tex); }); imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = ImageUtilities.Invert(tex); });
slideCollectionContainer.slideCollection = slideCollection; slideCollectionContainer.slideCollection = slideCollection;
@ -254,19 +234,7 @@ namespace NewHorizons.Builder.Props
var slidesCount = slides.Length; var slidesCount = slides.Length;
var slideCollection = new SlideCollection(slidesCount); var slideCollection = new SlideCollection(slidesCount);
var imageLoader = AddAsyncLoader(g, mod, info.slides, ref slideCollection);
var imageLoader = g.AddComponent<ImageUtilities.AsyncImageLoader>();
for (int i = 0; i < slidesCount; i++)
{
var slide = new Slide();
var slideInfo = slides[i];
imageLoader.pathsToLoad.Add(mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath);
AddModules(slideInfo, ref slide, mod);
slideCollection.slides[i] = slide;
}
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = tex; }); imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = tex; });
// attach a component to store all the data for the slides that play when a vision torch scans this target // attach a component to store all the data for the slides that play when a vision torch scans this target
@ -328,19 +296,8 @@ namespace NewHorizons.Builder.Props
var slidesCount = slides.Length; var slidesCount = slides.Length;
var slideCollection = new SlideCollection(slidesCount); var slideCollection = new SlideCollection(slidesCount);
var imageLoader = standingTorch.AddComponent<ImageUtilities.AsyncImageLoader>(); var imageLoader = AddAsyncLoader(standingTorch, mod, slides, ref slideCollection);
for (int i = 0; i < slidesCount; i++)
{
var slide = new Slide();
var slideInfo = slides[i];
imageLoader.pathsToLoad.Add(mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath);
AddModules(slideInfo, ref slide, mod);
slideCollection.slides[i] = slide;
}
// This variable just lets us track how many of the slides have been loaded. // This variable just lets us track how many of the slides have been loaded.
// This way as soon as the last one is loaded (due to async loading, this may be // This way as soon as the last one is loaded (due to async loading, this may be
// slide 7, or slide 3, or whatever), we can enable the vision torch. This allows us // slide 7, or slide 3, or whatever), we can enable the vision torch. This allows us
@ -375,6 +332,32 @@ namespace NewHorizons.Builder.Props
return standingTorch; return standingTorch;
} }
private static ImageUtilities.AsyncImageLoader AddAsyncLoader(GameObject gameObject, IModBehaviour mod, SlideInfo[] slides, ref SlideCollection slideCollection)
{
var imageLoader = gameObject.AddComponent<ImageUtilities.AsyncImageLoader>();
for (int i = 0; i < slides.Length; i++)
{
var slide = new Slide();
var slideInfo = slides[i];
if (string.IsNullOrEmpty(slideInfo.imagePath))
{
imageLoader.imageLoadedEvent?.Invoke(Texture2D.blackTexture, i);
}
else
{
// Don't use Path.Combine here else you break the Vision
imageLoader.PathsToLoad.Add((i, mod.ModHelper.Manifest.ModFolderPath + slideInfo.imagePath));
}
AddModules(slideInfo, ref slide, mod);
slideCollection.slides[i] = slide;
}
return imageLoader;
}
private static void AddModules(PropModule.SlideInfo slideInfo, ref Slide slide, IModBehaviour mod) private static void AddModules(PropModule.SlideInfo slideInfo, ref Slide slide, IModBehaviour mod)
{ {
var modules = new List<SlideFunctionModule>(); var modules = new List<SlideFunctionModule>();

View File

@ -14,6 +14,11 @@ namespace NewHorizons.External.Configs
[JsonObject] [JsonObject]
public class StarSystemConfig public class StarSystemConfig
{ {
/// <summary>
/// An override value for the far clip plane. Allows you to see farther.
/// </summary>
public float farClipPlaneOverride;
/// <summary> /// <summary>
/// Whether this system can be warped to via the warp drive. If you set factRequiredForWarp, this will be true. /// Whether this system can be warped to via the warp drive. If you set factRequiredForWarp, this will be true.
/// </summary> /// </summary>

View File

@ -39,7 +39,7 @@ namespace NewHorizons.Handlers
private static void AddCreditsSection(string sectionName, string[] entries, ref XmlDocument xml) private static void AddCreditsSection(string sectionName, string[] entries, ref XmlDocument xml)
{ {
var finalCredits = xml.SelectSingleNode("Credits/section"); var finalCredits = xml.SelectSingleNode("Credits/section[@name='CreditsFinal']");
/* /*
* Looks bad, would need more customization, complicated, messes up music timing, wont do for now * Looks bad, would need more customization, complicated, messes up music timing, wont do for now
@ -134,11 +134,8 @@ namespace NewHorizons.Handlers
{ {
var rootSection = MakeNode(doc, "section", new Dictionary<string, string>() var rootSection = MakeNode(doc, "section", new Dictionary<string, string>()
{ {
{ "platform", "All" }, { "name", "Custom" },
{ "type", "Scroll" }, { "credits-type", "Final Fast Krazy" }
{ "scrollDuration", "214" },
{ "spacing", "12" },
{ "width", "1590" }
}); });
var titleLayout = MakeNode(doc, "layout", new Dictionary<string, string>() var titleLayout = MakeNode(doc, "layout", new Dictionary<string, string>()

View File

@ -1,4 +1,5 @@
using HarmonyLib; using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
namespace NewHorizons.Patches namespace NewHorizons.Patches
@ -10,11 +11,11 @@ namespace NewHorizons.Patches
[HarmonyPatch(typeof(MapController), nameof(MapController.Awake))] [HarmonyPatch(typeof(MapController), nameof(MapController.Awake))]
public static void MapController_Awake(MapController __instance) public static void MapController_Awake(MapController __instance)
{ {
__instance._maxPanDistance = Main.FurthestOrbit * 1.5f; __instance._maxPanDistance = Mathf.Max(__instance._maxPanDistance, Main.FurthestOrbit * 1.5f);
__instance._maxZoomDistance *= 6f; __instance._maxZoomDistance *= 6f;
__instance._minPitchAngle = -90f; __instance._minPitchAngle = -90f;
__instance._zoomSpeed *= 4f; __instance._zoomSpeed *= 4f;
__instance._mapCamera.farClipPlane = Main.FurthestOrbit * 10f; __instance._mapCamera.farClipPlane = Mathf.Max(__instance._mapCamera.farClipPlane, Main.FurthestOrbit * 10f);
} }
[HarmonyPostfix] [HarmonyPostfix]

View File

@ -1,4 +1,4 @@
using HarmonyLib; using HarmonyLib;
namespace NewHorizons.Patches namespace NewHorizons.Patches
{ {
[HarmonyPatch] [HarmonyPatch]
@ -8,25 +8,12 @@ namespace NewHorizons.Patches
[HarmonyPatch(typeof(OWCamera), nameof(OWCamera.Awake))] [HarmonyPatch(typeof(OWCamera), nameof(OWCamera.Awake))]
public static void OnOWCameraAwake(OWCamera __instance) public static void OnOWCameraAwake(OWCamera __instance)
{ {
// var oldDist = __instance.farClipPlane; if (Main.SystemDict.TryGetValue(Main.Instance.CurrentStarSystem, out var system) && system?.Config?.farClipPlaneOverride != 0f)
// var newDist = __instance.farClipPlane * 10f; {
// if (__instance.useFarCamera) Mathf.Clamp(newDist, oldDist, 50000f); __instance.farClipPlane = system.Config.farClipPlaneOverride;
// else newDist = Mathf.Clamp(newDist, oldDist, 10000000f); __instance.farCameraDistance = system.Config.farClipPlaneOverride;
// __instance.farClipPlane = newDist; __instance.mainCamera.farClipPlane = system.Config.farClipPlaneOverride;
// __instance.farCameraDistance = newDist; }
// __instance.mainCamera.farClipPlane = newDist;
} }
// [HarmonyPrefix]
// [HarmonyPatch(typeof(OWCamera), nameof(OWCamera.RebuildSkybox))]
// public static bool OnOWCameraRebuildSkybox(OWCamera __instance)
// {
// __instance._skyboxCommandBuffer = new CommandBuffer();
// __instance._skyboxCommandBuffer.name = "Skybox";
// var camera = __instance._useFarCamera && !SystemInfo.usesReversedZBuffer ? __instance._farCamera : __instance._mainCamera;
// CameraEvent evt = CameraEvent.BeforeSkybox;
// camera.AddCommandBuffer(evt, __instance._skyboxCommandBuffer);
// return false;
// }
} }
} }

View File

@ -5,6 +5,11 @@
"description": "Configuration for a specific star system", "description": "Configuration for a specific star system",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"farClipPlaneOverride": {
"type": "number",
"description": "An override value for the far clip plane. Allows you to see farther.",
"format": "float"
},
"canEnterViaWarpDrive": { "canEnterViaWarpDrive": {
"type": "boolean", "type": "boolean",
"description": "Whether this system can be warped to via the warp drive. If you set factRequiredForWarp, this will be true.", "description": "Whether this system can be warped to via the warp drive. If you set factRequiredForWarp, this will be true.",

View File

@ -1,12 +1,14 @@
using OWML.Common; using OWML.Common;
using OWML.ModHelper;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Security.Policy;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
using UnityEngine.Networking; using UnityEngine.Networking;
using UnityEngine.UIElements;
namespace NewHorizons.Utility namespace NewHorizons.Utility
{ {
@ -128,7 +130,7 @@ namespace NewHorizons.Utility
var texture = (new Texture2D(size * 4, size * 4, TextureFormat.ARGB32, false)); var texture = (new Texture2D(size * 4, size * 4, TextureFormat.ARGB32, false));
texture.name = "SlideReelAtlas"; texture.name = "SlideReelAtlas";
Color[] fillPixels = new Color[size * size * 4 * 4]; var fillPixels = new Color[size * size * 4 * 4];
for (int xIndex = 0; xIndex < 4; xIndex++) for (int xIndex = 0; xIndex < 4; xIndex++)
{ {
for (int yIndex = 0; yIndex < 4; yIndex++) for (int yIndex = 0; yIndex < 4; yIndex++)
@ -276,8 +278,8 @@ namespace NewHorizons.Utility
{ {
var tex = (new Texture2D(1, 1, TextureFormat.ARGB32, false)); var tex = (new Texture2D(1, 1, TextureFormat.ARGB32, false));
tex.name = "Clear"; tex.name = "Clear";
Color fillColor = Color.clear; var fillColor = Color.clear;
Color[] fillPixels = new Color[tex.width * tex.height]; var fillPixels = new Color[tex.width * tex.height];
for (int i = 0; i < fillPixels.Length; i++) for (int i = 0; i < fillPixels.Length; i++)
{ {
fillPixels[i] = fillColor; fillPixels[i] = fillColor;
@ -296,7 +298,7 @@ namespace NewHorizons.Utility
{ {
var tex = (new Texture2D(width, height, TextureFormat.ARGB32, false)); var tex = (new Texture2D(width, height, TextureFormat.ARGB32, false));
tex.name = src.name + "CanvasScaled"; tex.name = src.name + "CanvasScaled";
Color[] fillPixels = new Color[tex.width * tex.height]; var fillPixels = new Color[tex.width * tex.height];
for (int i = 0; i < tex.width; i++) for (int i = 0; i < tex.width; i++)
{ {
for (int j = 0; j < tex.height; j++) for (int j = 0; j < tex.height; j++)
@ -339,14 +341,14 @@ namespace NewHorizons.Utility
} }
public static Texture2D MakeSolidColorTexture(int width, int height, Color color) public static Texture2D MakeSolidColorTexture(int width, int height, Color color)
{ {
Color[] pixels = new Color[width*height]; var pixels = new Color[width*height];
for(int i = 0; i < pixels.Length; i++) for(int i = 0; i < pixels.Length; i++)
{ {
pixels[i] = color; pixels[i] = color;
} }
Texture2D newTexture = new Texture2D(width, height); var newTexture = new Texture2D(width, height);
newTexture.SetPixels(pixels); newTexture.SetPixels(pixels);
newTexture.Apply(); newTexture.Apply();
return newTexture; return newTexture;
@ -364,10 +366,15 @@ namespace NewHorizons.Utility
// Modified from https://stackoverflow.com/a/69141085/9643841 // Modified from https://stackoverflow.com/a/69141085/9643841
public class AsyncImageLoader : MonoBehaviour public class AsyncImageLoader : MonoBehaviour
{ {
public List<string> pathsToLoad = new List<string>(); public List<(int index, string path)> PathsToLoad { get; private set; } = new ();
public class ImageLoadedEvent : UnityEvent<Texture2D, int> { } public class ImageLoadedEvent : UnityEvent<Texture2D, int> { }
public ImageLoadedEvent imageLoadedEvent = new ImageLoadedEvent(); public ImageLoadedEvent imageLoadedEvent = new ();
private readonly object _lockObj = new();
public bool FinishedLoading { get; private set; }
private int _loadedCount = 0;
// TODO: set up an optional “StartLoading” and “StartUnloading” condition on AsyncTextureLoader, // TODO: set up an optional “StartLoading” and “StartUnloading” condition on AsyncTextureLoader,
// and make use of that for at least for projector stuff (require player to be in the same sector as the slides // and make use of that for at least for projector stuff (require player to be in the same sector as the slides
@ -375,39 +382,59 @@ namespace NewHorizons.Utility
void Start() void Start()
{ {
for (int i = 0; i < pathsToLoad.Count; i++) imageLoadedEvent.AddListener(OnImageLoaded);
foreach (var (index, path) in PathsToLoad)
{ {
StartCoroutine(DownloadTexture(pathsToLoad[i], i)); StartCoroutine(DownloadTexture(path, index));
}
}
private void OnImageLoaded(Texture texture, int index)
{
lock (_lockObj)
{
_loadedCount++;
if (_loadedCount >= PathsToLoad.Count)
{
Logger.LogVerbose($"Finished loading all textures for {gameObject.name} (one was {PathsToLoad.FirstOrDefault()}");
FinishedLoading = true;
}
} }
} }
IEnumerator DownloadTexture(string url, int index) IEnumerator DownloadTexture(string url, int index)
{ {
if (_loadedTextures.ContainsKey(url)) lock(_loadedTextures)
{ {
Logger.LogVerbose($"Already loaded image at path: {url}"); if (_loadedTextures.ContainsKey(url))
var texture = _loadedTextures[url]; {
imageLoadedEvent.Invoke(texture, index); Logger.LogVerbose($"Already loaded image {index}:{url}");
yield break; var texture = _loadedTextures[url];
imageLoadedEvent?.Invoke(texture, index);
yield break;
}
} }
using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url)) using UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(url);
yield return uwr.SendWebRequest();
var hasError = uwr.error != null && uwr.error != "";
if (hasError)
{ {
yield return uwr.SendWebRequest(); Logger.LogError($"Failed to load {index}:{url} - {uwr.error}");
}
else
{
var texture = DownloadHandlerTexture.GetContent(uwr);
var hasError = uwr.error != null && uwr.error != ""; lock(_loadedTextures)
if (hasError) // (uwr.result != UnityWebRequest.Result.Success)
{ {
Debug.Log(uwr.error);
}
else
{
var texture = DownloadHandlerTexture.GetContent(uwr);
if (_loadedTextures.ContainsKey(url)) if (_loadedTextures.ContainsKey(url))
{ {
Logger.LogVerbose($"Already loaded image at path: {url}"); Logger.LogVerbose($"Already loaded image {index}:{url}");
Destroy(texture); Destroy(texture);
texture = _loadedTextures[url]; texture = _loadedTextures[url];
} }
@ -416,7 +443,7 @@ namespace NewHorizons.Utility
_loadedTextures.Add(url, texture); _loadedTextures.Add(url, texture);
} }
imageLoadedEvent.Invoke(texture, index); imageLoadedEvent?.Invoke(texture, index);
} }
} }
} }