using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace CaptainAudio
{
public static class AudioLoader
{
private class LoadTask
{
public string FolderName;
public string ClipName;
public byte[] AudioData;
public bool IsCompleted;
public AudioClip LoadedClip;
}
[CompilerGenerated]
private sealed class <>c__DisplayClass2_0
{
public string resourcePrefix;
internal bool <LoadEmbeddedResourcesParallel>b__0(string name)
{
return name.StartsWith(resourcePrefix);
}
}
[CompilerGenerated]
private sealed class <>c__DisplayClass3_0
{
public AudioClip clip;
public bool success;
internal void <LoadSingleClipWithRetry>b__0(AudioClip loadedClip)
{
clip = loadedClip;
success = (Object)(object)loadedClip != (Object)null;
}
}
[CompilerGenerated]
private sealed class <CollectAudioFiles>d__6 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public string path;
public Dictionary<string, AudioClip> singleDict;
public Dictionary<string, Dictionary<string, AudioClip>> folderDict;
private string[] <>s__1;
private int <>s__2;
private string <file>5__3;
private string[] <>s__4;
private int <>s__5;
private string <folder>5__6;
private string <folderName>5__7;
private string[] <>s__8;
private int <>s__9;
private string <file>5__10;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <CollectAudioFiles>d__6(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>s__1 = null;
<file>5__3 = null;
<>s__4 = null;
<folder>5__6 = null;
<folderName>5__7 = null;
<>s__8 = null;
<file>5__10 = null;
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>s__1 = Directory.GetFiles(path);
<>s__2 = 0;
goto IL_009a;
case 1:
<>1__state = -1;
<file>5__3 = null;
<>s__2++;
goto IL_009a;
case 2:
{
<>1__state = -1;
<file>5__10 = null;
<>s__9++;
goto IL_0182;
}
IL_009a:
if (<>s__2 < <>s__1.Length)
{
<file>5__3 = <>s__1[<>s__2];
<>2__current = LoadExternalClip(<file>5__3, singleDict);
<>1__state = 1;
return true;
}
<>s__1 = null;
<>s__4 = Directory.GetDirectories(path);
<>s__5 = 0;
goto IL_01b6;
IL_01b6:
if (<>s__5 < <>s__4.Length)
{
<folder>5__6 = <>s__4[<>s__5];
<folderName>5__7 = Path.GetFileName(<folder>5__6);
folderDict[<folderName>5__7] = new Dictionary<string, AudioClip>();
<>s__8 = Directory.GetFiles(<folder>5__6);
<>s__9 = 0;
goto IL_0182;
}
<>s__4 = null;
return false;
IL_0182:
if (<>s__9 < <>s__8.Length)
{
<file>5__10 = <>s__8[<>s__9];
<>2__current = LoadExternalClip(<file>5__10, folderDict[<folderName>5__7]);
<>1__state = 2;
return true;
}
<>s__8 = null;
<folderName>5__7 = null;
<folder>5__6 = null;
<>s__5++;
goto IL_01b6;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <InitializeAsync>d__1 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
private int <totalMusic>5__1;
private int <totalAmbient>5__2;
private int <totalSFX>5__3;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <InitializeAsync>d__1(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
if (_isInitialized)
{
return false;
}
CleanupOldTempFiles();
Plugin.CustomMusic.Clear();
Plugin.CustomAmbient.Clear();
Plugin.CustomSFX.Clear();
Plugin.CustomMusicList.Clear();
Plugin.CustomAmbientList.Clear();
Plugin.CustomSFXList.Clear();
<>2__current = LoadEmbeddedResourcesParallel("CaptainAudio.asset.Resources.Music", Plugin.CustomMusic, Plugin.CustomMusicList);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
<>2__current = LoadEmbeddedResourcesParallel("CaptainAudio.asset.Resources.Ambient", Plugin.CustomAmbient, Plugin.CustomAmbientList);
<>1__state = 2;
return true;
case 2:
<>1__state = -1;
<>2__current = LoadEmbeddedResourcesParallel("CaptainAudio.asset.Resources.SFX", Plugin.CustomSFX, Plugin.CustomSFXList);
<>1__state = 3;
return true;
case 3:
<>1__state = -1;
<>2__current = LoadExternalAudioFiles();
<>1__state = 4;
return true;
case 4:
<>1__state = -1;
StringMatchCache.Initialize();
_isInitialized = true;
<totalMusic>5__1 = Plugin.CustomMusic.Count + Plugin.CustomMusicList.Values.Sum((Dictionary<string, AudioClip> d) => d.Count);
<totalAmbient>5__2 = Plugin.CustomAmbient.Count + Plugin.CustomAmbientList.Values.Sum((Dictionary<string, AudioClip> d) => d.Count);
<totalSFX>5__3 = Plugin.CustomSFX.Count + Plugin.CustomSFXList.Values.Sum((Dictionary<string, AudioClip> d) => d.Count);
Plugin.Log.LogWarning((object)"=== 오디오 로딩 완료 ===");
Plugin.Log.LogInfo((object)$" 음악: {Plugin.CustomMusicList.Count}개 폴더, {<totalMusic>5__1}개 클립");
Plugin.Log.LogInfo((object)$" 환경음: {Plugin.CustomAmbientList.Count}개 폴더, {<totalAmbient>5__2}개 클립");
Plugin.Log.LogInfo((object)$" 효과음: {Plugin.CustomSFXList.Count}개 폴더, {<totalSFX>5__3}개 클립");
Plugin.Log.LogInfo((object)$" 총 {<totalMusic>5__1 + <totalAmbient>5__2 + <totalSFX>5__3}개 클립 로딩 완료");
return false;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <LoadAudioClipFromBytes>d__4 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public byte[] audioData;
public string clipName;
public Action<AudioClip> onComplete;
private string <fileExtension>5__1;
private string <tempPath>5__2;
private AudioType <audioType>5__3;
private string <uri>5__4;
private Exception <ex>5__5;
private UnityWebRequest <www>5__6;
private DownloadHandlerAudioClip <handler>5__7;
private AudioClip <clip>5__8;
private Exception <ex>5__9;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <LoadAudioClipFromBytes>d__4(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
int num = <>1__state;
if ((uint)(num - -4) <= 1u || num == 1)
{
try
{
if (num == -4 || num == 1)
{
try
{
}
finally
{
<>m__Finally2();
}
}
}
finally
{
<>m__Finally1();
}
}
<fileExtension>5__1 = null;
<tempPath>5__2 = null;
<uri>5__4 = null;
<ex>5__5 = null;
<www>5__6 = null;
<handler>5__7 = null;
<clip>5__8 = null;
<ex>5__9 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Expected O, but got Unknown
//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
//IL_01a9: Invalid comparison between Unknown and I4
try
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<fileExtension>5__1 = DetectAudioFormat(audioData);
<tempPath>5__2 = Path.Combine(Application.temporaryCachePath, $"temp_audio_{clipName}_{Guid.NewGuid()}{<fileExtension>5__1}");
try
{
Directory.CreateDirectory(Path.GetDirectoryName(<tempPath>5__2));
File.WriteAllBytes(<tempPath>5__2, audioData);
}
catch (Exception ex)
{
<ex>5__5 = ex;
Plugin.Log.LogWarning((object)("임시 파일 쓰기 실패 (" + clipName + "): " + <ex>5__5.Message));
onComplete?.Invoke(null);
return false;
}
<audioType>5__3 = GetAudioType(<fileExtension>5__1);
<uri>5__4 = "file:///" + <tempPath>5__2.Replace("\\", "/");
<>1__state = -3;
<www>5__6 = UnityWebRequestMultimedia.GetAudioClip(<uri>5__4, <audioType>5__3);
<>1__state = -4;
<handler>5__7 = (DownloadHandlerAudioClip)<www>5__6.downloadHandler;
<handler>5__7.streamAudio = true;
<www>5__6.timeout = Plugin.LoadTimeout.Value;
<>2__current = <www>5__6.SendWebRequest();
<>1__state = 1;
return true;
case 1:
<>1__state = -4;
if ((int)<www>5__6.result == 1)
{
<clip>5__8 = DownloadHandlerAudioClip.GetContent(<www>5__6);
if ((Object)(object)<clip>5__8 != (Object)null && <clip>5__8.length > 0f)
{
((Object)<clip>5__8).name = clipName;
onComplete?.Invoke(<clip>5__8);
}
else
{
Plugin.Log.LogWarning((object)("오디오 클립 로딩 실패 (" + clipName + "): 클립이 null이거나 길이가 0입니다."));
onComplete?.Invoke(null);
}
<clip>5__8 = null;
}
else
{
Plugin.Log.LogWarning((object)("오디오 클립 로딩 실패 (" + clipName + "): " + <www>5__6.error));
onComplete?.Invoke(null);
}
<handler>5__7 = null;
<>m__Finally2();
<www>5__6 = null;
<>m__Finally1();
return false;
}
}
catch
{
//try-fault
((IDisposable)this).Dispose();
throw;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
private void <>m__Finally1()
{
<>1__state = -1;
if (File.Exists(<tempPath>5__2))
{
try
{
File.Delete(<tempPath>5__2);
}
catch (Exception ex)
{
<ex>5__9 = ex;
Plugin.Log.LogWarning((object)("임시 파일 삭제 실패: " + <tempPath>5__2 + " - " + <ex>5__9.Message));
}
}
}
private void <>m__Finally2()
{
<>1__state = -3;
if (<www>5__6 != null)
{
((IDisposable)<www>5__6).Dispose();
}
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <LoadEmbeddedResourcesParallel>d__2 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public string resourcePrefix;
public Dictionary<string, AudioClip> singleDict;
public Dictionary<string, Dictionary<string, AudioClip>> folderDict;
private <>c__DisplayClass2_0 <>8__1;
private Assembly <assembly>5__2;
private string[] <resourceNames>5__3;
private List<LoadTask> <tasks>5__4;
private string[] <>s__5;
private int <>s__6;
private string <resourceName>5__7;
private Stream <stream>5__8;
private byte[] <audioData>5__9;
private string <fileName>5__10;
private string <folderName>5__11;
private string <clipName>5__12;
private LoadTask <task>5__13;
private List<LoadTask>.Enumerator <>s__14;
private LoadTask <task>5__15;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <LoadEmbeddedResourcesParallel>d__2(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>8__1 = null;
<assembly>5__2 = null;
<resourceNames>5__3 = null;
<tasks>5__4 = null;
<>s__5 = null;
<resourceName>5__7 = null;
<stream>5__8 = null;
<audioData>5__9 = null;
<fileName>5__10 = null;
<folderName>5__11 = null;
<clipName>5__12 = null;
<task>5__13 = null;
<>s__14 = default(List<LoadTask>.Enumerator);
<task>5__15 = null;
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>8__1 = new <>c__DisplayClass2_0();
<>8__1.resourcePrefix = resourcePrefix;
<assembly>5__2 = Assembly.GetExecutingAssembly();
<resourceNames>5__3 = (from name in <assembly>5__2.GetManifestResourceNames()
where name.StartsWith(<>8__1.resourcePrefix)
select name).ToArray();
if (<resourceNames>5__3.Length == 0)
{
return false;
}
<tasks>5__4 = new List<LoadTask>();
<>s__5 = <resourceNames>5__3;
for (<>s__6 = 0; <>s__6 < <>s__5.Length; <>s__6++)
{
<resourceName>5__7 = <>s__5[<>s__6];
<stream>5__8 = <assembly>5__2.GetManifestResourceStream(<resourceName>5__7);
if (<stream>5__8 != null)
{
<audioData>5__9 = new byte[<stream>5__8.Length];
<stream>5__8.Read(<audioData>5__9, 0, <audioData>5__9.Length);
<stream>5__8.Dispose();
<fileName>5__10 = <resourceName>5__7.Substring(<>8__1.resourcePrefix.Length + 1);
(<folderName>5__11, <clipName>5__12) = ParseResourcePath(<fileName>5__10);
if (!string.IsNullOrEmpty(<clipName>5__12))
{
<task>5__13 = new LoadTask
{
FolderName = <folderName>5__11,
ClipName = <clipName>5__12,
AudioData = <audioData>5__9,
IsCompleted = false,
LoadedClip = null
};
<tasks>5__4.Add(<task>5__13);
((MonoBehaviour)Plugin.instance).StartCoroutine(LoadSingleClipWithRetry(<task>5__13));
<stream>5__8 = null;
<audioData>5__9 = null;
<fileName>5__10 = null;
<folderName>5__11 = null;
<clipName>5__12 = null;
<task>5__13 = null;
<resourceName>5__7 = null;
}
}
}
<>s__5 = null;
break;
case 1:
<>1__state = -1;
break;
}
if (<tasks>5__4.Any((LoadTask t) => !t.IsCompleted))
{
<>2__current = null;
<>1__state = 1;
return true;
}
<>s__14 = <tasks>5__4.GetEnumerator();
try
{
while (<>s__14.MoveNext())
{
<task>5__15 = <>s__14.Current;
if ((Object)(object)<task>5__15.LoadedClip == (Object)null)
{
continue;
}
if (!string.IsNullOrEmpty(<task>5__15.FolderName))
{
if (!folderDict.ContainsKey(<task>5__15.FolderName))
{
folderDict[<task>5__15.FolderName] = new Dictionary<string, AudioClip>();
}
folderDict[<task>5__15.FolderName][<task>5__15.ClipName] = <task>5__15.LoadedClip;
}
else
{
singleDict[<task>5__15.ClipName] = <task>5__15.LoadedClip;
}
<task>5__15 = null;
}
}
finally
{
((IDisposable)<>s__14).Dispose();
}
<>s__14 = default(List<LoadTask>.Enumerator);
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <LoadExternalAudioFiles>d__5 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
private string <externalPath>5__1;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <LoadExternalAudioFiles>d__5(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<externalPath>5__1 = null;
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<externalPath>5__1 = Path.Combine(Paths.PluginPath, "CaptainAudio");
if (!Directory.Exists(<externalPath>5__1))
{
return false;
}
if (Directory.Exists(Path.Combine(<externalPath>5__1, "Music")))
{
<>2__current = CollectAudioFiles(Path.Combine(<externalPath>5__1, "Music"), Plugin.CustomMusic, Plugin.CustomMusicList);
<>1__state = 1;
return true;
}
goto IL_00b3;
case 1:
<>1__state = -1;
goto IL_00b3;
case 2:
<>1__state = -1;
goto IL_0103;
case 3:
{
<>1__state = -1;
break;
}
IL_00b3:
if (Directory.Exists(Path.Combine(<externalPath>5__1, "SFX")))
{
<>2__current = CollectAudioFiles(Path.Combine(<externalPath>5__1, "SFX"), Plugin.CustomSFX, Plugin.CustomSFXList);
<>1__state = 2;
return true;
}
goto IL_0103;
IL_0103:
if (Directory.Exists(Path.Combine(<externalPath>5__1, "Ambient")))
{
<>2__current = CollectAudioFiles(Path.Combine(<externalPath>5__1, "Ambient"), Plugin.CustomAmbient, Plugin.CustomAmbientList);
<>1__state = 3;
return true;
}
break;
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <LoadExternalClip>d__7 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public string path;
public Dictionary<string, AudioClip> dict;
private string <uri>5__1;
private UnityWebRequest <www>5__2;
private DownloadHandlerAudioClip <handler>5__3;
private AudioClip <clip>5__4;
private string <clipName>5__5;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <LoadExternalClip>d__7(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
int num = <>1__state;
if (num == -3 || num == 1)
{
try
{
}
finally
{
<>m__Finally1();
}
}
<uri>5__1 = null;
<www>5__2 = null;
<handler>5__3 = null;
<clip>5__4 = null;
<clipName>5__5 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Invalid comparison between Unknown and I4
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Expected O, but got Unknown
try
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
if (path.EndsWith(".txt") || !path.Contains("."))
{
return false;
}
<uri>5__1 = "file:///" + path.Replace("\\", "/");
<www>5__2 = UnityWebRequestMultimedia.GetAudioClip(<uri>5__1, (AudioType)0);
<>1__state = -3;
<www>5__2.timeout = Plugin.LoadTimeout.Value;
<>2__current = <www>5__2.SendWebRequest();
<>1__state = 1;
return true;
case 1:
<>1__state = -3;
if ((int)<www>5__2.result == 1)
{
<handler>5__3 = (DownloadHandlerAudioClip)<www>5__2.downloadHandler;
DownloadHandlerAudioClip obj = <handler>5__3;
<clip>5__4 = ((obj != null) ? obj.audioClip : null);
if ((Object)(object)<clip>5__4 != (Object)null)
{
<clipName>5__5 = Path.GetFileNameWithoutExtension(path);
((Object)<clip>5__4).name = <clipName>5__5;
dict[<clipName>5__5] = <clip>5__4;
Plugin.Log.LogInfo((object)("외부 오디오 로딩 성공: " + <clipName>5__5));
<clipName>5__5 = null;
}
else
{
Plugin.Log.LogWarning((object)("외부 오디오 로딩 실패 (클립 null): " + path));
}
<handler>5__3 = null;
<clip>5__4 = null;
}
else
{
Plugin.Log.LogWarning((object)("외부 오디오 로딩 실패: " + path + " - " + <www>5__2.error));
}
<>m__Finally1();
<www>5__2 = null;
return false;
}
}
catch
{
//try-fault
((IDisposable)this).Dispose();
throw;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
private void <>m__Finally1()
{
<>1__state = -1;
if (<www>5__2 != null)
{
((IDisposable)<www>5__2).Dispose();
}
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <LoadSingleClipWithRetry>d__3 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public LoadTask task;
private int <retryCount>5__1;
private int <attempt>5__2;
private <>c__DisplayClass3_0 <>8__3;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <LoadSingleClipWithRetry>d__3(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>8__3 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<retryCount>5__1 = Plugin.LoadRetryCount.Value;
<attempt>5__2 = 0;
break;
case 1:
<>1__state = -1;
if (<>8__3.success)
{
task.LoadedClip = <>8__3.clip;
task.IsCompleted = true;
return false;
}
if (<attempt>5__2 < <retryCount>5__1 - 1)
{
Plugin.Log.LogInfo((object)$"오디오 로딩 재시도 중... ({<attempt>5__2 + 1}/{<retryCount>5__1}): {task.ClipName}");
<>2__current = (object)new WaitForSeconds(Plugin.LoadRetryDelay.Value);
<>1__state = 2;
return true;
}
goto IL_015a;
case 2:
{
<>1__state = -1;
goto IL_015a;
}
IL_015a:
<>8__3 = null;
<attempt>5__2++;
break;
}
if (<attempt>5__2 < <retryCount>5__1)
{
<>8__3 = new <>c__DisplayClass3_0();
<>8__3.success = false;
<>8__3.clip = null;
<>2__current = LoadAudioClipFromBytes(task.AudioData, task.ClipName, delegate(AudioClip loadedClip)
{
<>8__3.clip = loadedClip;
<>8__3.success = (Object)(object)loadedClip != (Object)null;
});
<>1__state = 1;
return true;
}
task.IsCompleted = true;
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private static bool _isInitialized;
[IteratorStateMachine(typeof(<InitializeAsync>d__1))]
public static IEnumerator InitializeAsync()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <InitializeAsync>d__1(0);
}
[IteratorStateMachine(typeof(<LoadEmbeddedResourcesParallel>d__2))]
private static IEnumerator LoadEmbeddedResourcesParallel(string resourcePrefix, Dictionary<string, AudioClip> singleDict, Dictionary<string, Dictionary<string, AudioClip>> folderDict)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <LoadEmbeddedResourcesParallel>d__2(0)
{
resourcePrefix = resourcePrefix,
singleDict = singleDict,
folderDict = folderDict
};
}
[IteratorStateMachine(typeof(<LoadSingleClipWithRetry>d__3))]
private static IEnumerator LoadSingleClipWithRetry(LoadTask task)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <LoadSingleClipWithRetry>d__3(0)
{
task = task
};
}
[IteratorStateMachine(typeof(<LoadAudioClipFromBytes>d__4))]
private static IEnumerator LoadAudioClipFromBytes(byte[] audioData, string clipName, Action<AudioClip> onComplete)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <LoadAudioClipFromBytes>d__4(0)
{
audioData = audioData,
clipName = clipName,
onComplete = onComplete
};
}
[IteratorStateMachine(typeof(<LoadExternalAudioFiles>d__5))]
private static IEnumerator LoadExternalAudioFiles()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <LoadExternalAudioFiles>d__5(0);
}
[IteratorStateMachine(typeof(<CollectAudioFiles>d__6))]
private static IEnumerator CollectAudioFiles(string path, Dictionary<string, AudioClip> singleDict, Dictionary<string, Dictionary<string, AudioClip>> folderDict)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <CollectAudioFiles>d__6(0)
{
path = path,
singleDict = singleDict,
folderDict = folderDict
};
}
[IteratorStateMachine(typeof(<LoadExternalClip>d__7))]
private static IEnumerator LoadExternalClip(string path, Dictionary<string, AudioClip> dict)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <LoadExternalClip>d__7(0)
{
path = path,
dict = dict
};
}
private static (string folderName, string clipName) ParseResourcePath(string fileName)
{
string item = null;
string item2 = null;
if (fileName.Contains("\\"))
{
string[] array = fileName.Split('\\');
if (array.Length >= 2)
{
item = array[0];
item2 = Path.GetFileNameWithoutExtension(array[^1]);
}
}
else
{
string[] array2 = fileName.Split('.');
if (array2.Length >= 3)
{
item = array2[0];
item2 = string.Join(".", array2.Skip(1).Take(array2.Length - 2));
}
else if (array2.Length >= 2)
{
item = null;
item2 = array2[0];
}
}
return (item, item2);
}
private static void CleanupOldTempFiles()
{
try
{
string temporaryCachePath = Application.temporaryCachePath;
if (!Directory.Exists(temporaryCachePath))
{
return;
}
string[] files = Directory.GetFiles(temporaryCachePath, "temp_audio_*");
int num = 0;
string[] array = files;
foreach (string text in array)
{
try
{
FileInfo fileInfo = new FileInfo(text);
if ((DateTime.Now - fileInfo.LastWriteTime).TotalHours > 1.0)
{
File.Delete(text);
num++;
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("임시 파일 정리 실패: " + text + " - " + ex.Message));
}
}
}
catch (Exception ex2)
{
Plugin.Log.LogWarning((object)("임시 파일 정리 중 오류: " + ex2.Message));
}
}
private static string DetectAudioFormat(byte[] audioData)
{
if (audioData.Length < 4)
{
return ".ogg";
}
if (audioData[0] == 82 && audioData[1] == 73 && audioData[2] == 70 && audioData[3] == 70)
{
return ".wav";
}
if ((audioData[0] == 73 && audioData[1] == 68 && audioData[2] == 51) || (audioData[0] == byte.MaxValue && (audioData[1] & 0xE0) == 224))
{
return ".mp3";
}
return ".ogg";
}
private static AudioType GetAudioType(string extension)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
if (!(extension == ".wav"))
{
if (extension == ".mp3")
{
return (AudioType)13;
}
return (AudioType)14;
}
return (AudioType)20;
}
}
[HarmonyPatch(typeof(MusicMan), "Awake")]
public static class MusicMan_Awake_Patch
{
private static void Postfix(MusicMan __instance)
{
if (!Plugin.ModEnabled.Value)
{
return;
}
for (int i = 0; i < __instance.m_music.Count; i++)
{
NamedMusic instance = __instance.m_music[i];
string value = ReflectionCache.GetValue<string>(instance, "m_name");
if (Plugin.CustomMusicList.ContainsKey(value))
{
AudioClip[] value2 = Plugin.CustomMusicList[value].Values.ToArray();
ReflectionCache.SetValue(instance, "m_clips", value2);
continue;
}
string text = StringMatchCache.FindMatch(value);
if (text != null && Plugin.CustomMusicList.ContainsKey(text))
{
AudioClip[] value3 = Plugin.CustomMusicList[text].Values.ToArray();
ReflectionCache.SetValue(instance, "m_clips", value3);
continue;
}
AudioClip[] value4 = ReflectionCache.GetValue<AudioClip[]>(instance, "m_clips");
if (value4 == null)
{
continue;
}
for (int j = 0; j < value4.Length; j++)
{
if ((Object)(object)value4[j] != (Object)null && Plugin.CustomMusic.ContainsKey(((Object)value4[j]).name))
{
value4[j] = Plugin.CustomMusic[((Object)value4[j]).name];
}
}
}
}
}
[HarmonyPatch(typeof(MusicMan), "UpdateMusic")]
public static class MusicMan_UpdateMusic_Patch
{
private static void Prefix(ref object ___m_queuedMusic, AudioSource ___m_musicSource)
{
if (Plugin.ModEnabled.Value)
{
if (___m_queuedMusic != null)
{
ReflectionCache.SetValue(___m_queuedMusic, "m_volume", Plugin.MusicVolume.Value);
}
if (!___m_musicSource.isPlaying && ___m_musicSource.loop)
{
___m_musicSource.loop = false;
}
}
}
}
[HarmonyPatch(typeof(MusicLocation), "Awake")]
public static class MusicLocation_Awake_Patch
{
private static void Postfix(ref AudioSource ___m_audioSource, ref float ___m_baseVolume)
{
if (Plugin.ModEnabled.Value && !((Object)(object)___m_audioSource == (Object)null) && !((Object)(object)___m_audioSource.clip == (Object)null))
{
string name = ((Object)___m_audioSource.clip).name;
if (Plugin.CustomMusic.ContainsKey(name))
{
___m_audioSource.clip = Plugin.CustomMusic[name];
___m_baseVolume *= Plugin.LocationVolMultiplier.Value;
}
}
}
}
[HarmonyPatch(typeof(AudioMan), "Awake")]
public static class AudioMan_Awake_Patch
{
private static void Postfix(AudioMan __instance, IList ___m_randomAmbients, AudioSource ___m_oceanAmbientSource, AudioSource ___m_windLoopSource)
{
if (Plugin.ModEnabled.Value)
{
for (int i = 0; i < ___m_randomAmbients.Count; i++)
{
object obj = ___m_randomAmbients[i];
string value = ReflectionCache.GetValue<string>(obj, "m_name");
ReplaceAmbientClips(obj, "m_randomAmbientClips");
ReplaceAmbientClips(obj, "m_randomAmbientClipsDay");
ReplaceAmbientClips(obj, "m_randomAmbientClipsNight");
ReplaceAmbientList(obj, value, "_day", "m_randomAmbientClipsDay");
ReplaceAmbientList(obj, value, "_night", "m_randomAmbientClipsNight");
ReplaceAmbientList(obj, value, "", "m_randomAmbientClips");
}
if (Plugin.CustomAmbient.ContainsKey("ocean"))
{
___m_oceanAmbientSource.clip = Plugin.CustomAmbient["ocean"];
}
if (Plugin.CustomAmbient.ContainsKey("wind"))
{
___m_windLoopSource.clip = Plugin.CustomAmbient["wind"];
}
}
}
private static void ReplaceAmbientClips(object ambient, string fieldName)
{
IList value = ReflectionCache.GetValue<IList>(ambient, fieldName);
if (value == null)
{
return;
}
for (int i = 0; i < value.Count; i++)
{
object? obj = value[i];
AudioClip val = (AudioClip)((obj is AudioClip) ? obj : null);
if ((Object)(object)val != (Object)null && Plugin.CustomAmbient.ContainsKey(((Object)val).name))
{
value[i] = Plugin.CustomAmbient[((Object)val).name];
}
}
}
private static void ReplaceAmbientList(object ambient, string ambientName, string suffix, string fieldName)
{
string key = ambientName + suffix;
if (!Plugin.CustomAmbientList.ContainsKey(key))
{
return;
}
IList value = ReflectionCache.GetValue<IList>(ambient, fieldName);
if (value == null)
{
return;
}
List<AudioClip> list = Plugin.CustomAmbientList[key].Values.ToList();
value.Clear();
foreach (AudioClip item in list)
{
value.Add(item);
}
}
}
[HarmonyPatch(typeof(AudioMan), "QueueAmbientLoop")]
public static class AudioMan_QueueAmbientLoop_Patch
{
private static void Prefix(ref float ___m_queuedAmbientVol, ref float ___m_ambientVol, ref float vol)
{
if (Plugin.ModEnabled.Value)
{
vol = Plugin.AmbientVolume.Value;
___m_ambientVol = Plugin.AmbientVolume.Value;
___m_queuedAmbientVol = Plugin.AmbientVolume.Value;
}
}
}
[HarmonyPatch(typeof(ZSFX), "Awake")]
public static class ZSFX_Awake_Patch
{
private static void Postfix(ZSFX __instance)
{
if (!Plugin.ModEnabled.Value)
{
return;
}
string zSFXName = AudioUtils.GetZSFXName(__instance);
if (Plugin.CustomSFXList.TryGetValue(zSFXName, out var value))
{
__instance.m_audioClips = (from x in value
orderby x.Key
select x.Value).ToArray();
}
else
{
if (__instance.m_audioClips == null)
{
return;
}
for (int i = 0; i < __instance.m_audioClips.Length; i++)
{
if ((Object)(object)__instance.m_audioClips[i] != (Object)null && Plugin.CustomSFX.ContainsKey(((Object)__instance.m_audioClips[i]).name))
{
__instance.m_audioClips[i] = Plugin.CustomSFX[((Object)__instance.m_audioClips[i]).name];
}
}
}
}
}
[HarmonyPatch(typeof(TeleportWorld), "Awake")]
public static class TeleportWorld_Awake_Patch
{
private static void Postfix(TeleportWorld __instance)
{
if (Plugin.ModEnabled.Value && Plugin.CustomSFX.ContainsKey("portal"))
{
AudioSource componentInChildren = ((Component)__instance).GetComponentInChildren<AudioSource>();
if ((Object)(object)componentInChildren != (Object)null)
{
componentInChildren.clip = Plugin.CustomSFX["portal"];
((Component)componentInChildren).gameObject.SetActive(false);
((Component)componentInChildren).gameObject.SetActive(true);
}
}
}
}
[HarmonyPatch(typeof(Fireplace), "Start")]
public static class Fireplace_Start_Patch
{
private static readonly Dictionary<string, string> FireplaceSFXMapping = new Dictionary<string, string>
{
{ "groundtorch", "groundtorch" },
{ "walltorch", "walltorch" },
{ "fire_pit", "fire_pit" },
{ "bonfire", "bonfire" },
{ "hearth", "hearth" }
};
private static void Postfix(Fireplace __instance)
{
if (!Plugin.ModEnabled.Value)
{
return;
}
string name = ((Object)__instance).name;
foreach (KeyValuePair<string, string> item in FireplaceSFXMapping)
{
if (name.Contains(item.Key) && Plugin.CustomSFX.ContainsKey(item.Value))
{
AudioSource fireplaceAudioSource = GetFireplaceAudioSource(__instance, item.Key);
if ((Object)(object)fireplaceAudioSource != (Object)null)
{
fireplaceAudioSource.clip = Plugin.CustomSFX[item.Value];
}
break;
}
}
}
private static AudioSource GetFireplaceAudioSource(Fireplace fireplace, string keyword)
{
if (keyword == "groundtorch")
{
GameObject enabledObject = fireplace.m_enabledObject;
return (enabledObject != null) ? enabledObject.GetComponentInChildren<AudioSource>() : null;
}
if (keyword == "walltorch")
{
GameObject enabledObjectHigh = fireplace.m_enabledObjectHigh;
AudioSource val = ((enabledObjectHigh != null) ? enabledObjectHigh.GetComponentInChildren<AudioSource>() : null);
object obj = val;
if (obj == null)
{
GameObject enabledObject2 = fireplace.m_enabledObject;
obj = ((enabledObject2 != null) ? enabledObject2.GetComponentInChildren<AudioSource>() : null);
}
return (AudioSource)obj;
}
GameObject enabledObjectHigh2 = fireplace.m_enabledObjectHigh;
return (enabledObjectHigh2 != null) ? enabledObjectHigh2.GetComponentInChildren<AudioSource>() : null;
}
}
[HarmonyPatch(typeof(EnvMan), "Awake")]
public static class EnvMan_Awake_Patch
{
private static void Postfix(EnvMan __instance)
{
if (!Plugin.ModEnabled.Value)
{
return;
}
for (int i = 0; i < __instance.m_environments.Count; i++)
{
string name = __instance.m_environments[i].m_name;
foreach (string key in Plugin.CustomMusicList.Keys)
{
string text = name.ToLower();
string text2 = key.ToLower();
if (text == text2 || text.Contains(text2) || text2.Contains(text))
{
string name2 = __instance.m_environments[i].m_name;
__instance.m_environments[i].m_name = key;
AddMusicToEnvironment(__instance, i, "");
__instance.m_environments[i].m_name = name2;
break;
}
}
string[] array = new string[4] { "Morning", "Day", "Evening", "Night" };
string[] array2 = array;
foreach (string timeOfDay in array2)
{
AddMusicToEnvironment(__instance, i, timeOfDay);
}
}
}
private static void AddMusicToEnvironment(EnvMan envMan, int index, string timeOfDay)
{
string text = envMan.m_environments[index].m_name + timeOfDay;
if (Plugin.CustomMusicList.ContainsKey(text))
{
switch (timeOfDay)
{
case "Morning":
envMan.m_environments[index].m_musicMorning = text;
break;
case "Day":
envMan.m_environments[index].m_musicDay = text;
break;
case "Evening":
envMan.m_environments[index].m_musicEvening = text;
break;
case "Night":
envMan.m_environments[index].m_musicNight = text;
break;
}
Type type = ((object)MusicMan.instance.m_music[0]).GetType();
object obj = Activator.CreateInstance(type);
ReflectionCache.SetValue(obj, "m_name", text);
ReflectionCache.SetValue(obj, "m_clips", (from x in Plugin.CustomMusicList[text]
orderby x.Key
select x.Value).ToArray());
ReflectionCache.SetValue(obj, "m_loop", true);
ReflectionCache.SetValue(obj, "m_ambientMusic", true);
ReflectionCache.SetValue(obj, "m_resume", true);
((IList)MusicMan.instance.m_music).Add(obj);
}
}
}
[HarmonyPatch(typeof(Terminal), "InputText")]
public static class Terminal_InputText_Patch
{
private static bool Prefix(Terminal __instance)
{
if (!Plugin.ModEnabled.Value)
{
return true;
}
FieldInfo field = ((object)__instance).GetType().GetField("m_input");
if (field == null)
{
return true;
}
object value = field.GetValue(__instance);
if (value == null)
{
return true;
}
PropertyInfo property = value.GetType().GetProperty("text");
if (property == null)
{
return true;
}
string text = (string)property.GetValue(value);
switch (text.ToLower())
{
case "captainaudio reset":
((BaseUnityPlugin)Plugin.instance).Config.Reload();
((BaseUnityPlugin)Plugin.instance).Config.Save();
AddOutput(__instance, text);
AddOutput(__instance, "<color=#00BFFF>Captain Audio config reloaded</color>");
return false;
case "captainaudio music":
AddOutput(__instance, text);
if ((Object)(object)EnvMan.instance != (Object)null)
{
Player localPlayer = Player.m_localPlayer;
string arg = ((localPlayer != null && localPlayer.IsSafeInHome()) ? "home" : EnvMan.instance.GetAmbientMusic());
AddOutput(__instance, $"<color=#00BFFF>Current: {arg} | Folders: {Plugin.CustomMusicList.Count} | Clips: {Plugin.CustomMusic.Count}</color>");
}
return false;
case "captainaudio env":
AddOutput(__instance, text);
if ((Object)(object)EnvMan.instance != (Object)null)
{
AddOutput(__instance, "<color=#00BFFF>Environment: " + EnvMan.instance.GetCurrentEnvironment().m_name + "</color>");
}
else
{
AddOutput(__instance, "<color=#00BFFF>Must be called in-game</color>");
}
return false;
default:
return true;
}
}
private static void AddOutput(Terminal terminal, string text)
{
Traverse.Create((object)terminal).Method("AddString", new object[1] { text }).GetValue();
}
}
[BepInPlugin("captain.CaptainAudio", "Captain Audio", "1.2.1")]
public class Plugin : BaseUnityPlugin
{
public static Plugin instance;
public static ConfigEntry<bool> ModEnabled;
public static ConfigEntry<float> MusicVolume;
public static ConfigEntry<float> AmbientVolume;
public static ConfigEntry<float> LocationVolMultiplier;
public static ConfigEntry<int> LoadRetryCount;
public static ConfigEntry<float> LoadRetryDelay;
public static ConfigEntry<int> LoadTimeout;
public static ConfigEntry<bool> EnableFallback;
public static Dictionary<string, AudioClip> CustomMusic = new Dictionary<string, AudioClip>();
public static Dictionary<string, Dictionary<string, AudioClip>> CustomMusicList = new Dictionary<string, Dictionary<string, AudioClip>>();
public static Dictionary<string, AudioClip> CustomAmbient = new Dictionary<string, AudioClip>();
public static Dictionary<string, Dictionary<string, AudioClip>> CustomAmbientList = new Dictionary<string, Dictionary<string, AudioClip>>();
public static Dictionary<string, AudioClip> CustomSFX = new Dictionary<string, AudioClip>();
public static Dictionary<string, Dictionary<string, AudioClip>> CustomSFXList = new Dictionary<string, Dictionary<string, AudioClip>>();
public static ManualLogSource Log { get; private set; }
private void Awake()
{
instance = this;
Log = ((BaseUnityPlugin)this).Logger;
ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this mod");
MusicVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MusicVolume", 0.6f, "Music volume (0.0 - 1.0)");
AmbientVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "AmbientVolume", 0.3f, "Ambient volume (0.0 - 1.0)");
LocationVolMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "LocationVolumeMultiplier", 5f, "Location music volume multiplier");
LoadRetryCount = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "LoadRetryCount", 3, "Number of retries when audio loading fails");
LoadRetryDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "LoadRetryDelay", 0.5f, "Delay between retries in seconds");
LoadTimeout = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "LoadTimeout", 15, "Timeout for audio loading in seconds");
EnableFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "EnableFallback", true, "Use fallback to vanilla music on load failure");
if (!ModEnabled.Value)
{
return;
}
SetupConfigEvents();
try
{
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
((MonoBehaviour)this).StartCoroutine(AudioLoader.InitializeAsync());
Log.LogInfo((object)"Captain Audio v1.2.1 loaded");
}
catch (Exception ex)
{
Log.LogError((object)("Critical error: " + ex.Message));
}
}
private void SetupConfigEvents()
{
MusicVolume.SettingChanged += delegate
{
Log.LogInfo((object)$"음악 볼륨 변경: {MusicVolume.Value:F2} (다음 음악부터 적용됨)");
};
AmbientVolume.SettingChanged += delegate
{
Log.LogInfo((object)$"환경음 볼륨 변경: {AmbientVolume.Value:F2} (다음 환경음부터 적용됨)");
};
LocationVolMultiplier.SettingChanged += delegate
{
Log.LogInfo((object)$"Location 음악 볼륨 배율 변경: {LocationVolMultiplier.Value:F2} (다음 음악부터 적용됨)");
};
LoadRetryCount.SettingChanged += delegate
{
Log.LogInfo((object)$"오디오 로딩 재시도 횟수 변경: {LoadRetryCount.Value}");
};
LoadRetryDelay.SettingChanged += delegate
{
Log.LogInfo((object)$"재시도 지연 시간 변경: {LoadRetryDelay.Value}초");
};
LoadTimeout.SettingChanged += delegate
{
Log.LogInfo((object)$"로딩 타임아웃 변경: {LoadTimeout.Value}초");
};
}
}
public static class AudioUtils
{
public static string GetZSFXName(ZSFX zsfx)
{
string name = ((Object)zsfx).name;
char[] anyOf = new char[2] { '(', ' ' };
int num = name.IndexOfAny(anyOf);
return (num != -1) ? name.Remove(num) : name;
}
public static void SafeSetVolume(AudioSource source, float volume)
{
if ((Object)(object)source != (Object)null)
{
source.volume = Mathf.Clamp01(volume);
}
}
}
public static class ReflectionCache
{
private static readonly ConcurrentDictionary<string, FieldInfo> _fieldCache = new ConcurrentDictionary<string, FieldInfo>();
private static readonly ConcurrentDictionary<string, PropertyInfo> _propertyCache = new ConcurrentDictionary<string, PropertyInfo>();
public static FieldInfo GetField(Type type, string fieldName)
{
string key = type.FullName + "." + fieldName;
return _fieldCache.GetOrAdd(key, (string _) => type.GetField(fieldName));
}
public static void SetValue(object instance, string fieldName, object value)
{
GetField(instance.GetType(), fieldName)?.SetValue(instance, value);
}
public static T GetValue<T>(object instance, string fieldName)
{
FieldInfo field = GetField(instance.GetType(), fieldName);
return (field != null) ? ((T)field.GetValue(instance)) : default(T);
}
}
public static class StringMatchCache
{
private static readonly Dictionary<string, string> _lowerCaseCache = new Dictionary<string, string>();
private static readonly Dictionary<string, string> _musicMappingCache = new Dictionary<string, string>();
private static bool _initialized = false;
public static string GetLowerCase(string input)
{
if (string.IsNullOrEmpty(input))
{
return string.Empty;
}
if (!_lowerCaseCache.ContainsKey(input))
{
_lowerCaseCache[input] = input.ToLower();
}
return _lowerCaseCache[input];
}
public static void Initialize()
{
if (!_initialized)
{
AddMapping("menu", "menu", "start", "intro", "mainmenu", "main_menu", "title");
AddMapping("meadows", "meadow", "meadows");
AddMapping("blackforest", "forest", "dark", "blackforest");
AddMapping("swamp", "swamp");
_initialized = true;
}
}
private static void AddMapping(string target, params string[] sources)
{
foreach (string text in sources)
{
_musicMappingCache[text + "->" + target] = target;
}
}
public static string FindMatch(string musicName)
{
if (string.IsNullOrEmpty(musicName))
{
return null;
}
if (Plugin.CustomMusicList.ContainsKey(musicName))
{
return musicName;
}
if (_musicMappingCache.ContainsKey(musicName))
{
return _musicMappingCache[musicName];
}
string lowerCase = GetLowerCase(musicName);
foreach (string key in Plugin.CustomMusicList.Keys)
{
string lowerCase2 = GetLowerCase(key);
if (lowerCase.Contains(lowerCase2) || lowerCase2.Contains(lowerCase))
{
_musicMappingCache[musicName] = key;
return key;
}
}
return null;
}
}
}