SHA256
forked from ADOFAIEditorForum/ADOFAIRenderer
Initial Commit
This commit is contained in:
commit
44a22ae103
19 files changed
+772
No files matched your search
+35
@@ -0,0 +1,35 @@
|
|||||||
|
## Build outputs
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
Bin/
|
||||||
|
Obj/
|
||||||
|
build/
|
||||||
|
Build/
|
||||||
|
|
||||||
|
## IDE and Editor Settings
|
||||||
|
# Visual Studio
|
||||||
|
.vs/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
*.userprefs
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# JetBrains Rider / IntelliJ
|
||||||
|
.idea/
|
||||||
|
*.sln.DotSettings.user
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/code-snippets
|
||||||
|
|
||||||
|
## OS-specific files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
desktop.ini
|
||||||
|
|
||||||
|
## Agent Metadata
|
||||||
|
.antigravitycli/
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<NoWarn>MSB3277</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="0Harmony">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\MelonLoader\net35\0Harmony.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Assembly-CSharp-firstpass">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="MelonLoader">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\MelonLoader\net35\MelonLoader.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="RDTools">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\RDTools.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="SkyHook.Unity">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\SkyHook.Unity.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Unity.TextMeshPro">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\Unity.TextMeshPro.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AssetBundleModule">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.AudioModule">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.InputLegacyModule">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.InputModule">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.InputModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UI">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.UI.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UIElementsModule">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UIModule">
|
||||||
|
<HintPath>$(ADOFAI_PATH)\A Dance of Fire and Ice_Data\Managed\UnityEngine.UIModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Bundle\Win64\fonts" />
|
||||||
|
<EmbeddedResource Include="Bundle\Win64\fonts" />
|
||||||
|
<None Remove="Bundle\Win64\scenes" />
|
||||||
|
<EmbeddedResource Include="Bundle\Win64\scenes" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ADOFAIRenderer", "ADOFAIRenderer.csproj", "{2D997D97-A2CC-4EB0-8963-DA6A71082319}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{2D997D97-A2CC-4EB0-8963-DA6A71082319}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2D997D97-A2CC-4EB0-8963-DA6A71082319}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2D997D97-A2CC-4EB0-8963-DA6A71082319}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2D997D97-A2CC-4EB0-8963-DA6A71082319}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,13 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Component
|
||||||
|
{
|
||||||
|
[DefaultExecutionOrder(-2147483648)]
|
||||||
|
public class FirstUpdate : MonoBehaviour
|
||||||
|
{
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
RenderMod.OnFirstUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Component
|
||||||
|
{
|
||||||
|
public class RenderManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
public static int Countdown = 0;
|
||||||
|
public static int FrameCount = 0;
|
||||||
|
public static bool SkipPressToStart = false;
|
||||||
|
public static string LevelPath = "";
|
||||||
|
public static RenderManager Instance = null!;
|
||||||
|
private static int _originalInputOffset;
|
||||||
|
|
||||||
|
public static RenderSettings Configuration;
|
||||||
|
|
||||||
|
public struct RenderSettings
|
||||||
|
{
|
||||||
|
public double TargetFPS;
|
||||||
|
public double VideoFPS;
|
||||||
|
|
||||||
|
public int RenderWidth;
|
||||||
|
public int RenderHeight;
|
||||||
|
|
||||||
|
public int Bitrate;
|
||||||
|
public string Codec;
|
||||||
|
|
||||||
|
public RenderSettings(double targetFPS, double videoFPS, int renderWidth, int renderHeight, int bitrate, string codec)
|
||||||
|
{
|
||||||
|
TargetFPS = targetFPS;
|
||||||
|
VideoFPS = videoFPS;
|
||||||
|
|
||||||
|
RenderWidth = renderWidth;
|
||||||
|
RenderHeight = renderHeight;
|
||||||
|
|
||||||
|
Bitrate = bitrate;
|
||||||
|
Codec = codec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool _renderSetup;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (_renderSetup && ADOBase.lm)
|
||||||
|
{
|
||||||
|
ADOBase.lm.hideDifficultyUI = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_renderSetup && scnGame.instance && !scnGame.instance.isLoading)
|
||||||
|
{
|
||||||
|
_renderSetup = false;
|
||||||
|
scrCamera.instance.forceRTCam = true;
|
||||||
|
scrCamera.instance.SetupRTCam(true);
|
||||||
|
|
||||||
|
_originalInputOffset = scrConductor.currentPreset.inputOffset;
|
||||||
|
scrConductor.currentPreset.inputOffset = 0;
|
||||||
|
RDC.auto = true;
|
||||||
|
|
||||||
|
RenderMod.IsRendering = true;
|
||||||
|
Countdown = 3;
|
||||||
|
|
||||||
|
scrController.instance.StartCoroutine(SetupPlay());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RenderMod.IsRendering && scrController.instance.state == States.Won)
|
||||||
|
{
|
||||||
|
RenderMod.IsRendering = RenderMod.IsCapturing = false;
|
||||||
|
scrConductor.currentPreset.inputOffset = _originalInputOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetupGameScene()
|
||||||
|
{
|
||||||
|
GCS.customLevelPaths = new[] { LevelPath };
|
||||||
|
GCS.checkpointNum = 0;
|
||||||
|
GCS.customLevelId = "";
|
||||||
|
GCS.nextSpeedRun = 1;
|
||||||
|
GCS.customLevelIndex = 0;
|
||||||
|
|
||||||
|
ADOBase.loader.LoadSceneWithTransition(WipeDirection.StartsFromRight, "scnGame");
|
||||||
|
SkipPressToStart = true;
|
||||||
|
_renderSetup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator SetupPlay()
|
||||||
|
{
|
||||||
|
for (; Countdown > 0; Countdown--)
|
||||||
|
{
|
||||||
|
yield return new WaitForSecondsRealtime(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameCount = 0;
|
||||||
|
RenderMod.IsCapturing = true;
|
||||||
|
scrController.instance.paused = scrController.instance.audioPaused = false;
|
||||||
|
scrController.instance.levelWasSkipped = true;
|
||||||
|
|
||||||
|
scrConductor.instance.song.clip = null;
|
||||||
|
scrConductor.instance.song.time = -1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Patch.ClassPatch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(scnEditor))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static class scnEditorPatch
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch("Start")]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static void AddButtonRender(scnEditor __instance)
|
||||||
|
{
|
||||||
|
var cloneTarget = __instance.buttonExit!.gameObject;
|
||||||
|
var buttonContainer = cloneTarget.transform.parent!;
|
||||||
|
|
||||||
|
var buttonObj = Object.Instantiate(cloneTarget, buttonContainer)!;
|
||||||
|
buttonObj.name = "buttonRender";
|
||||||
|
|
||||||
|
var button = buttonObj.GetComponent<Button>()!;
|
||||||
|
// Clear persistent and non-persistent listeners from the original button
|
||||||
|
button.onClick = new Button.ButtonClickedEvent();
|
||||||
|
button.onClick.AddListener(RenderMod.StartRender);
|
||||||
|
|
||||||
|
// The button root has an Image component for the background (rounded box).
|
||||||
|
// We want to change the icon sprite, which is on a child GameObject.
|
||||||
|
var images = buttonObj.GetComponentsInChildren<Image>();
|
||||||
|
if (images.Length <= 1) return;
|
||||||
|
|
||||||
|
// ReSharper disable once Unity.UnknownResource
|
||||||
|
// images[0] is the background on the root, images[1] is the icon on the child
|
||||||
|
var sprite = Resources.Load<Sprite>("LevelEditor/LevelEvents/MoveCamera");
|
||||||
|
if (sprite != null)
|
||||||
|
{
|
||||||
|
var iconImage = images[1];
|
||||||
|
iconImage.sprite = sprite;
|
||||||
|
iconImage.rectTransform.sizeDelta = new Vector2(24, 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Patch.ClassPatch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(scrController))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static class scrControllerPatch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch("TogglePauseGame")]
|
||||||
|
public static bool PreventPause()
|
||||||
|
{
|
||||||
|
return !RenderMod.IsRendering;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using ADOFAIRenderer.Component;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Patch.ClassPatch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(scrPlayerManager))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static class scrPlayerManagerPatch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch("AnyValidInputWasTriggered")]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
private static bool IgnoreInput(ref bool __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsRendering) return true;
|
||||||
|
|
||||||
|
__result = RenderManager.Countdown == 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using ADOFAIRenderer.Component;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Patch.ClassPatch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(scrPressToStart))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public class scrPressToStartPatch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch("ShowText")]
|
||||||
|
private static bool PreventShowText()
|
||||||
|
{
|
||||||
|
if (!RenderManager.SkipPressToStart) return true;
|
||||||
|
|
||||||
|
RenderManager.SkipPressToStart = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using ADOFAIRenderer.Component;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Patch.ClassPatch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(scrShowIfDebug))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static class scrShowIfDebugPatch
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch("Update")]
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
private static void IgnoreInput(Text ___txt, Color ___defaultColor)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsRendering) return;
|
||||||
|
|
||||||
|
___txt.text = "Rendering";
|
||||||
|
if (RenderManager.Countdown > 0) ___txt.text += $" in {RenderManager.Countdown}..";
|
||||||
|
|
||||||
|
___txt.color = ___defaultColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using ADOFAIRenderer.Component;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Patch
|
||||||
|
{
|
||||||
|
public static class RenderEnvironmentPatches
|
||||||
|
{
|
||||||
|
private const bool RenderPatch = true;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Time), "time", MethodType.Getter)]
|
||||||
|
public static class TimePatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref float __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsCapturing || !RenderPatch) return true;
|
||||||
|
__result = (float)(RenderManager.FrameCount / RenderManager.Configuration.TargetFPS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Time), "timeAsDouble", MethodType.Getter)]
|
||||||
|
public static class TimeAsDoublePatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref double __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsCapturing || !RenderPatch) return true;
|
||||||
|
__result = RenderManager.FrameCount / RenderManager.Configuration.TargetFPS;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Time), "unscaledTime", MethodType.Getter)]
|
||||||
|
public static class UnscaledTimePatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref float __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsCapturing || !RenderPatch) return true;
|
||||||
|
__result = (float)(RenderManager.FrameCount / RenderManager.Configuration.TargetFPS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Time), "unscaledTimeAsDouble", MethodType.Getter)]
|
||||||
|
public static class UnscaledTimeAsDoublePatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref double __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsCapturing || !RenderPatch) return true;
|
||||||
|
__result = RenderManager.FrameCount / RenderManager.Configuration.TargetFPS;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(AudioSettings), "dspTime", MethodType.Getter)]
|
||||||
|
public static class DspTimePatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref double __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsCapturing || !RenderPatch) return true;
|
||||||
|
__result = RenderManager.FrameCount / RenderManager.Configuration.TargetFPS;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(AudioSource), "PlayScheduled")]
|
||||||
|
public static class PlayScheduledPatch
|
||||||
|
{
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static bool Prefix(AudioSource __instance, double time)
|
||||||
|
{
|
||||||
|
return !RenderMod.IsRendering || !RenderPatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Time), "frameCount", MethodType.Getter)]
|
||||||
|
public static class FrameCountPatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref int __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsCapturing || !RenderPatch) return true;
|
||||||
|
__result = RenderManager.FrameCount;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Time), "deltaTime", MethodType.Getter)]
|
||||||
|
public static class DeltaTimePatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref float __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsCapturing || !RenderPatch) return true;
|
||||||
|
__result = (float)(1 / RenderManager.Configuration.TargetFPS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Time), "unscaledDeltaTime", MethodType.Getter)]
|
||||||
|
public static class UnscaledDeltaTimePatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref float __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsCapturing || !RenderPatch) return true;
|
||||||
|
__result = (float)(1 / RenderManager.Configuration.TargetFPS);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Screen), "width", MethodType.Getter)]
|
||||||
|
public static class ScreenWidthPatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref int __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsRendering || !RenderPatch) return true;
|
||||||
|
__result = RenderManager.Configuration.RenderWidth;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Screen), "height", MethodType.Getter)]
|
||||||
|
public static class ScreenHeightPatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public static bool Prefix(ref int __result)
|
||||||
|
{
|
||||||
|
if (!RenderMod.IsRendering || !RenderPatch) return true;
|
||||||
|
__result = RenderManager.Configuration.RenderHeight;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Patch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(scrCamera), "SetCustomFrameRate")]
|
||||||
|
public class SetCustomFrameRatePatch
|
||||||
|
{
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
private static bool Prefix(scrCamera __instance, bool enable, float frame, ref MeshRenderer ___camQuadMesh, ref RenderTexture ___camRT)
|
||||||
|
{
|
||||||
|
// There is an issue that `mainTexture.Release` triggers even if `mainTexture` is `camRT`, so mod tries to fix it
|
||||||
|
if (enable || __instance.enableCustomFPS != enable) return true;
|
||||||
|
|
||||||
|
__instance.enableCustomFPS = enable;
|
||||||
|
__instance.frameRate = frame;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Patch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(scrHitTextManager), "ShowHitText")]
|
||||||
|
public class ShowHitTextPatch
|
||||||
|
{
|
||||||
|
public static bool Prefix()
|
||||||
|
{
|
||||||
|
return !RenderMod.IsRendering;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using ADOFAIRenderer;
|
||||||
|
using ADOFAIRenderer.Component;
|
||||||
|
using ADOFAIRenderer.Util;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
[assembly: MelonInfo(typeof(RenderMod), "ADOFAI Renderer", "0.0.1-INDEV", "ADOFAI Editor Forum")]
|
||||||
|
[assembly: MelonGame("7th Beat Games", "A Dance of Fire and Ice")]
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer
|
||||||
|
{
|
||||||
|
|
||||||
|
public class RenderMod : MelonMod
|
||||||
|
{
|
||||||
|
public static AssetBundle FontBundle = null!;
|
||||||
|
public static AssetBundle SceneBundle = null!;
|
||||||
|
public static bool WatchGameLoaded;
|
||||||
|
public static string[] ModScenes = {};
|
||||||
|
|
||||||
|
private static double _beforeTime = 0;
|
||||||
|
|
||||||
|
public static bool IsRendering = false;
|
||||||
|
public static bool IsCapturing = false;
|
||||||
|
|
||||||
|
public override void OnInitializeMelon()
|
||||||
|
{
|
||||||
|
var renderManagerObj = new GameObject("Render Manager");
|
||||||
|
var updateHookerObj = new GameObject("Update Hooker");
|
||||||
|
Object.DontDestroyOnLoad( renderManagerObj );
|
||||||
|
Object.DontDestroyOnLoad( updateHookerObj );
|
||||||
|
|
||||||
|
renderManagerObj.AddComponent<RenderManager>();
|
||||||
|
updateHookerObj.AddComponent<FirstUpdate>();
|
||||||
|
LoadBundles();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadBundles()
|
||||||
|
{
|
||||||
|
FontBundle = BundleLoader.GetBundle("fonts");
|
||||||
|
SceneBundle = BundleLoader.GetBundle("scenes");
|
||||||
|
ModScenes = SceneBundle.GetAllScenePaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FixEventSystem()
|
||||||
|
{
|
||||||
|
if (EventSystem.current == null) return;
|
||||||
|
var currentModule = EventSystem.current.currentInputModule;
|
||||||
|
|
||||||
|
if (currentModule != null) return;
|
||||||
|
MelonLogger.Msg("Unity 6 인풋 모듈 이식.");
|
||||||
|
|
||||||
|
var newModule = EventSystem.current.gameObject.AddComponent<StandaloneInputModule>();
|
||||||
|
newModule.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnFirstUpdate()
|
||||||
|
{
|
||||||
|
if (_beforeTime == 0) _beforeTime = Time.realtimeSinceStartupAsDouble;
|
||||||
|
|
||||||
|
var realDeltaTime = Time.realtimeSinceStartupAsDouble - _beforeTime;
|
||||||
|
_beforeTime = Time.realtimeSinceStartupAsDouble;
|
||||||
|
|
||||||
|
if (!IsRendering) return;
|
||||||
|
RenderManager.FrameCount++;
|
||||||
|
|
||||||
|
Time.timeScale = (float)(Time.deltaTime / realDeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void StartRender()
|
||||||
|
{
|
||||||
|
var targetMethod = typeof(scnEditor).GetMethod("TryApplicationQuit",
|
||||||
|
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
|
||||||
|
if (targetMethod == null || scnEditor.instance == null) return;
|
||||||
|
if (ADOBase.levelPath.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
scnEditor.instance.TryQuitToMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderManager.LevelPath = ADOBase.levelPath;
|
||||||
|
|
||||||
|
scnEditor.instance.CheckUnsavedChanges(() =>
|
||||||
|
{
|
||||||
|
var quitDelegate =
|
||||||
|
(Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), scnEditor.instance, targetMethod);
|
||||||
|
|
||||||
|
Application.wantsToQuit -= quitDelegate;
|
||||||
|
ADOBase.loader.LoadSceneWithTransition(WipeDirection.StartsFromRight, "Assets/Scenes/RenderSettingsScene.unity");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using ADOFAIRenderer.Component;
|
||||||
|
using MelonLoader;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.UI
|
||||||
|
{
|
||||||
|
public class RenderButton : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("Input Fields")]
|
||||||
|
[SerializeField] private TMP_InputField targetFPSInput = null!;
|
||||||
|
[SerializeField] private TMP_InputField videoFPSInput = null!;
|
||||||
|
[SerializeField] private TMP_InputField renderWidthInput = null!;
|
||||||
|
[SerializeField] private TMP_InputField renderHeightInput = null!;
|
||||||
|
[SerializeField] private TMP_InputField bitrateInput = null!;
|
||||||
|
|
||||||
|
[Header("Dropdown")]
|
||||||
|
[SerializeField] private TMP_Dropdown codecDropdown = null!;
|
||||||
|
|
||||||
|
private Button _buttonComponent = null!;
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
_buttonComponent = GetComponent<Button>();
|
||||||
|
_buttonComponent.onClick.AddListener(OnClick);
|
||||||
|
|
||||||
|
RenderMod.FixEventSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnClick()
|
||||||
|
{
|
||||||
|
if (IsAnyFieldEmpty()) return;
|
||||||
|
Melon<RenderMod>.Logger.Msg($"레벨 로드: {RenderManager.LevelPath}");
|
||||||
|
|
||||||
|
double.TryParse(targetFPSInput.text, out var targetFPS);
|
||||||
|
double.TryParse(videoFPSInput.text, out var videoFPS);
|
||||||
|
int.TryParse(renderWidthInput.text, out var renderWidth);
|
||||||
|
int.TryParse(renderHeightInput.text, out var renderHeight);
|
||||||
|
int.TryParse(bitrateInput.text, out var bitrate);
|
||||||
|
|
||||||
|
var selectedCodecIndex = codecDropdown.value;
|
||||||
|
var selectedCodecName = codecDropdown.options[selectedCodecIndex].text;
|
||||||
|
|
||||||
|
RenderManager.Configuration = new RenderManager.RenderSettings
|
||||||
|
{
|
||||||
|
TargetFPS = targetFPS,
|
||||||
|
VideoFPS = videoFPS,
|
||||||
|
RenderWidth = renderWidth,
|
||||||
|
RenderHeight = renderHeight,
|
||||||
|
Bitrate = bitrate,
|
||||||
|
Codec = selectedCodecName.ToLower(),
|
||||||
|
};
|
||||||
|
|
||||||
|
RenderManager.Instance.SetupGameScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAnyFieldEmpty()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(targetFPSInput.text)) return true;
|
||||||
|
if (string.IsNullOrWhiteSpace(videoFPSInput.text)) return true;
|
||||||
|
if (string.IsNullOrWhiteSpace(renderWidthInput.text)) return true;
|
||||||
|
if (string.IsNullOrWhiteSpace(renderHeightInput.text)) return true;
|
||||||
|
if (string.IsNullOrWhiteSpace(bitrateInput.text)) return true;
|
||||||
|
|
||||||
|
// 드롭다운은 기본적으로 항상 무언가 선택되어 있지만(0번 항목 등),
|
||||||
|
// 만약 '선택 안함(-1)' 같은 예외 처리가 필요하다면 아래처럼 검사할 수 있습니다.
|
||||||
|
if (codecDropdown.value < 0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Util
|
||||||
|
{
|
||||||
|
public static class BundleLoader
|
||||||
|
{
|
||||||
|
private static string BundlePlatform;
|
||||||
|
private static readonly Assembly? ExecutingAssembly;
|
||||||
|
|
||||||
|
static BundleLoader()
|
||||||
|
{
|
||||||
|
BundlePlatform = Application.platform switch
|
||||||
|
{
|
||||||
|
RuntimePlatform.WindowsPlayer => "Win64",
|
||||||
|
RuntimePlatform.OSXPlayer => "OSX",
|
||||||
|
_ => "Linux"
|
||||||
|
};
|
||||||
|
ExecutingAssembly = Assembly.GetExecutingAssembly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssetBundle GetBundle(string resourcePath)
|
||||||
|
{
|
||||||
|
if (ExecutingAssembly != null)
|
||||||
|
{
|
||||||
|
var bundlePath = $"ADOFAIRenderer.Bundle.{BundlePlatform}.{resourcePath}";
|
||||||
|
using var resourceStream = ExecutingAssembly.GetManifestResourceStream(bundlePath);
|
||||||
|
if (resourceStream != null)
|
||||||
|
{
|
||||||
|
return AssetBundle.LoadFromStream(resourceStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
Melon<RenderMod>.Logger.Error($"DLL에서 번들 리소스를 찾을 수 없습니다.\n{bundlePath}");
|
||||||
|
throw new MissingManifestResourceException("Could not find bundle resource in DLL.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Melon<RenderMod>.Logger.Error("실행 어셈블리가 제대로 설정되지 않았습니다.");
|
||||||
|
throw new InvalidOperationException("ExecutingAssembly has not been set.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.Util
|
||||||
|
{
|
||||||
|
public class WaitForFrames : CustomYieldInstruction
|
||||||
|
{
|
||||||
|
private int _targetFrameCount;
|
||||||
|
|
||||||
|
public WaitForFrames(int numberOfFrames)
|
||||||
|
{
|
||||||
|
_targetFrameCount = Time.frameCount + numberOfFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool keepWaiting => Time.frameCount < _targetFrameCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user