1
0
Fork 0

Compare commits

..

No commits in common. "work/r/en_US" and "master" have entirely different histories.

16 changed files with 134 additions and 227 deletions

3
.gitignore vendored
View File

@ -5,7 +5,4 @@ riderModule.iml
/_ReSharper.Caches/
.idea/
*.dll
.vs/
dist/
MuzikaGromche.sln.DotSettings.user
MuzikaGromche.zip

View File

@ -1,3 +1 @@
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text

BIN
Assets/GodModeLoop.ogg (Stored with Git LFS)

Binary file not shown.

BIN
Assets/GodModeStart.ogg (Stored with Git LFS)

Binary file not shown.

BIN
Assets/MuzikaGromcheLoop.mp3 (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/MuzikaGromcheLoop.ogg (Stored with Git LFS)

Binary file not shown.

BIN
Assets/MuzikaGromcheStart.mp3 (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Assets/MuzikaGromcheStart.ogg (Stored with Git LFS)

Binary file not shown.

BIN
Assets/PeretasovkaLoop.ogg (Stored with Git LFS)

Binary file not shown.

BIN
Assets/PeretasovkaStart.ogg (Stored with Git LFS)

Binary file not shown.

BIN
Assets/RiseAndShineLoop.ogg (Stored with Git LFS)

Binary file not shown.

BIN
Assets/RiseAndShineStart.ogg (Stored with Git LFS)

Binary file not shown.

View File

@ -10,21 +10,20 @@ using UnityEngine.Networking;
namespace MuzikaGromche
{
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class Plugin : BaseUnityPlugin
{
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class Plugin : BaseUnityPlugin
{
public static Track[] Tracks = [
new Track
{
Name = "MuzikaGromche",
WindUpTimer = 46.3f,
Bpm = 130f,
AudioType = AudioType.OGGVORBIS,
},
new Track
{
Name = "VseVZale",
WindUpTimer = 39f,
WindUpTimer = 39f,
Bpm = 138f,
},
new Track
@ -50,89 +49,20 @@ namespace MuzikaGromche
Name = "Durochka",
WindUpTimer = 37f,
Bpm = 130f,
},
new Track
{
Name = "GodMode",
WindUpTimer = 40.38f,
Bpm = 108f,
AudioType = AudioType.OGGVORBIS,
},
new Track
{
Name = "RiseAndShine",
WindUpTimer = 59.87f,
Bpm = 137.36f,
AudioType = AudioType.OGGVORBIS,
},
new Track
{
Name = "Peretasovka",
WindUpTimer = 59.04f,
Bpm = 130f,
AudioType = AudioType.OGGVORBIS,
},
}
];
public static Coroutine JesterLightSwitching;
public static Track CurrentTrack;
public static void StartLightSwitching(MonoBehaviour __instance)
{
StopLightSwitching(__instance);
JesterLightSwitching = __instance.StartCoroutine(rotateColors());
}
public static void StopLightSwitching(MonoBehaviour __instance)
{
if (JesterLightSwitching != null) {
__instance.StopCoroutine(JesterLightSwitching);
JesterLightSwitching = null;
}
}
public static void SetLightColor(Color color)
{
foreach (var light in RoundManager.Instance.allPoweredLights)
{
light.color = color;
}
}
public static void ResetLightColor()
{
SetLightColor(Color.white);
}
// TODO: Move to Track class to make them customizable per-song
static List<Color> colors = [Color.magenta, Color.cyan, Color.green, Color.yellow];
public static IEnumerator rotateColors()
{
Debug.Log("Starting color rotation");
var i = 0;
while (true)
{
var color = colors[i];
Debug.Log("Chose color " + color);
SetLightColor(color);
i = (i + 1) % colors.Count;
if (CurrentTrack != null) {
yield return new WaitForSeconds(60f / CurrentTrack.Bpm);
} else {
yield break;
}
}
}
private void Awake()
{
string text = Info.Location.TrimEnd((PluginInfo.PLUGIN_NAME + ".dll").ToCharArray());
UnityWebRequest[] requests = new UnityWebRequest[Tracks.Length * 2];
for (int i = 0; i < Tracks.Length; i++) {
Track track = Tracks[i];
requests[i * 2] = UnityWebRequestMultimedia.GetAudioClip($"File://{text}{track.FileNameStart}", track.AudioType);
requests[i * 2 + 1] = UnityWebRequestMultimedia.GetAudioClip($"File://{text}{track.FileNameLoop}", track.AudioType);
requests[i * 2] = UnityWebRequestMultimedia.GetAudioClip($"File://{text}{track.Name}Start.mp3", AudioType.MPEG);
requests[i * 2 + 1] = UnityWebRequestMultimedia.GetAudioClip($"File://{text}{track.Name}Loop.mp3", AudioType.MPEG);
requests[i * 2].SendWebRequest();
requests[i * 2 + 1].SendWebRequest();
}
@ -141,130 +71,141 @@ namespace MuzikaGromche
if (requests.All(request => request.result == UnityWebRequest.Result.Success)) {
for (int i = 0; i < Tracks.Length; i++) {
Track track = Tracks[i];
track.LoadedStart = DownloadHandlerAudioClip.GetContent(requests[i * 2]);
track.LoadedLoop = DownloadHandlerAudioClip.GetContent(requests[i * 2 + 1]);
Tracks[i].LoadedStart = DownloadHandlerAudioClip.GetContent(requests[i * 2]);
Tracks[i].LoadedLoop = DownloadHandlerAudioClip.GetContent(requests[i * 2 + 1]);
}
new Harmony(PluginInfo.PLUGIN_NAME).PatchAll(typeof(JesterPatch));
} else {
Logger.LogError("Could not load audio file");
}
}
}
}
public class Track
{
public string Name;
// Wind-up time can be shorter than the Start audio track, so that
// the "pop" effect can be baked in the Start audio and kept away
// from the looped part.
public float WindUpTimer;
// BPM for light switching in sync with the music. There is no offset,
// so the Loop track should start precisely on a beat.
public float Bpm;
public class Track
{
public string Name;
public float WindUpTimer;
public float Bpm;
public AudioClip LoadedStart;
public AudioClip LoadedLoop;
}
// MPEG is basically mp3, and it can produce gaps at the start.
// WAV is OK, but takes a lot of space. Try OGGVORBIS instead.
public AudioType AudioType = AudioType.MPEG;
[HarmonyPatch(typeof(JesterAI))]
internal class JesterPatch
{
[HarmonyPatch("Update")]
[HarmonyPrefix]
public static void DoNotStopTheMusicPrefix(JesterAI __instance, out State __state)
{
__state = new State();
__state.prevStateindex = __instance.previousState;
if (__instance.currentBehaviourStateIndex == 2 && __instance.previousBehaviourStateIndex != 2) {
// if just popped out
// then override farAudio so that vanilla logic does not stop the music
__state.farAudio = __instance.farAudio;
__instance.farAudio = __instance.creatureVoice;
}
}
static List<Color> colors = [Color.magenta, Color.cyan, Color.green, Color.yellow];
public AudioClip LoadedStart;
public AudioClip LoadedLoop;
public static IEnumerator rotateColors()
{
Debug.Log("Starting color rotation");
var i = 0;
while (true)
{
var color = colors[i];
Debug.Log("Chose color " + color);
foreach (var light in RoundManager.Instance.allPoweredLights)
{
light.color = color;
}
public string FileNameStart => $"{Name}Start.{ext}";
public string FileNameLoop => $"{Name}Loop.{ext}";
private string ext => AudioType switch
{
AudioType.MPEG => "mp3",
AudioType.WAV => "wav",
AudioType.OGGVORBIS => "ogg",
_ => "",
};
}
[HarmonyPatch(typeof(JesterAI))]
internal class JesterPatch
{
[HarmonyPatch("Update")]
[HarmonyPrefix]
public static void DoNotStopTheMusicPrefix(JesterAI __instance, out State __state)
{
__state = new State();
__state.prevStateindex = __instance.previousState;
if (__instance.currentBehaviourStateIndex == 2 && __instance.previousBehaviourStateIndex != 2) {
// if just popped out
// then override farAudio so that vanilla logic does not stop the music
__state.farAudio = __instance.farAudio;
__instance.farAudio = __instance.creatureVoice;
}
}
i += 1;
if (i >= colors.Count) i = 0;
yield return new WaitForSeconds(60f / Plugin.CurrentTrack.Bpm);
}
}
[HarmonyPatch("Update")]
[HarmonyPostfix]
public static void DoNotStopTheMusic(JesterAI __instance, State __state)
{
if (__state.farAudio != null)
{
__instance.farAudio = __state.farAudio;
}
[HarmonyPostfix]
public static void DoNotStopTheMusic(JesterAI __instance, State __state)
{
if (__state.farAudio != null)
{
__instance.farAudio = __state.farAudio;
}
if (__instance.currentBehaviourStateIndex is 1 && __state.prevStateindex != 1)
{
// if just started winding up
// then stop the default music...
__instance.farAudio.Stop();
__instance.creatureVoice.Stop();
// ...and start modded music
var seed = RoundManager.Instance.dungeonGenerator.Generator.ChosenSeed;
var sha = SHA256.Create();
var hash = sha.ComputeHash(BitConverter.GetBytes(seed));
var trackId = 0;
foreach (var t in hash)
{
// modulus division on byte array
trackId *= 256 % Plugin.Tracks.Length;
trackId %= Plugin.Tracks.Length;
trackId += t % Plugin.Tracks.Length;
trackId %= Plugin.Tracks.Length;
}
Debug.Log($"Seed is {seed}, chosen track is {trackId} out of {Plugin.Tracks.Length} tracks");
Plugin.CurrentTrack = Plugin.Tracks[trackId];
__instance.popUpTimer = Plugin.CurrentTrack.WindUpTimer;
__instance.farAudio.maxDistance = 150;
__instance.farAudio.clip = Plugin.CurrentTrack.LoadedStart;
__instance.farAudio.loop = false;
Debug.Log($"Playing start music: maxDistance: {__instance.farAudio.maxDistance}, minDistance: {__instance.farAudio.minDistance}, volume: {__instance.farAudio.volume}, spread: {__instance.farAudio.spread}");
__instance.farAudio.Play();
}
if (__instance.currentBehaviourStateIndex is 1 && __state.prevStateindex != 1)
{
// if just started winding up
// then stop the default music...
__instance.farAudio.Stop();
__instance.creatureVoice.Stop();
if (__instance.currentBehaviourStateIndex is 2 && __state.prevStateindex != 2)
{
__instance.creatureVoice.Stop();
if (Plugin.JesterLightSwitching != null) {
__instance.StopCoroutine(Plugin.JesterLightSwitching);
Plugin.JesterLightSwitching = null;
}
Plugin.JesterLightSwitching = __instance.StartCoroutine(rotateColors());
}
// ...and start modded music
var seed = RoundManager.Instance.dungeonGenerator.Generator.ChosenSeed;
var sha = SHA256.Create();
var hash = sha.ComputeHash(BitConverter.GetBytes(seed));
var trackId = 0;
foreach (var t in hash)
{
// modulus division on byte array
trackId *= 256 % Plugin.Tracks.Length;
trackId %= Plugin.Tracks.Length;
trackId += t % Plugin.Tracks.Length;
trackId %= Plugin.Tracks.Length;
}
Debug.Log($"Seed is {seed}, chosen track is {trackId} out of {Plugin.Tracks.Length} tracks");
Plugin.CurrentTrack = Plugin.Tracks[trackId];
__instance.popUpTimer = Plugin.CurrentTrack.WindUpTimer;
__instance.farAudio.maxDistance = 150;
__instance.farAudio.clip = Plugin.CurrentTrack.LoadedStart;
__instance.farAudio.loop = false;
Debug.Log($"Playing start music: maxDistance: {__instance.farAudio.maxDistance}, minDistance: {__instance.farAudio.minDistance}, volume: {__instance.farAudio.volume}, spread: {__instance.farAudio.spread}");
__instance.farAudio.Play();
}
if (__instance.currentBehaviourStateIndex != 2 && __state.prevStateindex == 2)
{
if (Plugin.JesterLightSwitching != null) {
__instance.StopCoroutine(Plugin.JesterLightSwitching);
Plugin.JesterLightSwitching = null;
}
foreach (var light in RoundManager.Instance.allPoweredLights)
{
light.color = Color.white;
}
}
if (__instance.currentBehaviourStateIndex is 2 && __state.prevStateindex != 2)
{
__instance.creatureVoice.Stop();
Plugin.StartLightSwitching(__instance);
}
if (__instance.currentBehaviourStateIndex is 2 && !__instance.creatureVoice.isPlaying)
{
__instance.creatureVoice.maxDistance = 150;
__instance.creatureVoice.clip = Plugin.CurrentTrack.LoadedLoop;
var time = __instance.farAudio.time;
var delay = Plugin.CurrentTrack.LoadedStart.length - time;
Debug.Log($"Start length: {Plugin.CurrentTrack.LoadedStart.length}; played time: {time}");
Debug.Log($"Playing loop music: maxDistance: {__instance.creatureVoice.maxDistance}, minDistance: {__instance.creatureVoice.minDistance}, volume: {__instance.creatureVoice.volume}, spread: {__instance.creatureVoice.spread}, in seconds: {delay}");
__instance.creatureVoice.PlayDelayed(delay);
}
}
}
if (__instance.currentBehaviourStateIndex != 2 && __state.prevStateindex == 2)
{
Plugin.StopLightSwitching(__instance);
Plugin.ResetLightColor();
}
if (__instance.currentBehaviourStateIndex is 2 && !__instance.creatureVoice.isPlaying)
{
__instance.creatureVoice.maxDistance = 150;
__instance.creatureVoice.clip = Plugin.CurrentTrack.LoadedLoop;
var time = __instance.farAudio.time;
var delay = Plugin.CurrentTrack.LoadedStart.length - time;
Debug.Log($"Start length: {Plugin.CurrentTrack.LoadedStart.length}; played time: {time}");
Debug.Log($"Playing loop music: maxDistance: {__instance.creatureVoice.maxDistance}, minDistance: {__instance.creatureVoice.minDistance}, volume: {__instance.creatureVoice.volume}, spread: {__instance.creatureVoice.spread}, in seconds: {delay}");
__instance.creatureVoice.PlayDelayed(delay);
}
}
}
internal class State
{
public AudioSource farAudio;
public int prevStateindex;
}
internal class State
{
public AudioSource farAudio;
public int prevStateindex;
}
}

View File

@ -1 +0,0 @@
Adds some content to your reverse teleports on Titan

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

View File

@ -1,10 +0,0 @@
{
"name": "MuzikaGromche",
"version_number": "13.37.6",
"author": "Oflor",
"description": "Glaza zakryvaj",
"website_url": "https://git.vilunov.me/nikita/muzika-gromche",
"dependencies": [
"BepInEx-BepInExPack-5.4.2100"
]
}