Improved plugins and added new
This commit is contained in:
1 parent
9f4f8bf523
commit
a740fec7c8
149 files changed
+4383
-199
No files matched your search
@@ -0,0 +1,735 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using BepInEx.Logging;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using FMODUnity;
|
||||
using Il2CppInterop.Runtime;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using Skopje.Modding;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Skopje.DomRadio
|
||||
{
|
||||
[BepInPlugin(PluginGuid, PluginName, PluginVersion)]
|
||||
public class DomRadioPlugin : BasePlugin
|
||||
{
|
||||
public const string PluginGuid = "com.skopje.domradio";
|
||||
public const string PluginName = "Skopje Dom Radio";
|
||||
public const string PluginVersion = "1.0.0";
|
||||
|
||||
internal static ManualLogSource LogSource;
|
||||
|
||||
internal static ConfigEntry<KeyCode> Toggle;
|
||||
internal static ConfigEntry<KeyCode> NextTrack;
|
||||
internal static ConfigEntry<KeyCode> PreviousTrack;
|
||||
internal static ConfigEntry<bool> Shuffle;
|
||||
internal static ConfigEntry<bool> MuteGameMusic;
|
||||
internal static ConfigEntry<string> MusicBusFilter;
|
||||
internal static ConfigEntry<string> Folder;
|
||||
internal static ConfigEntry<bool> ShowNowPlaying;
|
||||
|
||||
internal static SkopjePlayer LocalPlayer;
|
||||
|
||||
static GameObject _host;
|
||||
static Il2CppSystem.Action<SkopjePlayer> _onPlayerStarted;
|
||||
static Il2CppSystem.Action<SkopjePlayer> _onPlayerStopped;
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
LogSource = Log;
|
||||
Toggle = Config.Bind("Radio", "Toggle", KeyCode.F8, "Turn the radio on or off.");
|
||||
NextTrack = Config.Bind("Radio", "NextTrack", KeyCode.F10, "Skip to the next file.");
|
||||
PreviousTrack = Config.Bind("Radio", "PreviousTrack", KeyCode.F9, "Go back to the previous file.");
|
||||
Shuffle = Config.Bind("Radio", "Shuffle", false, "Play the folder in a random order. Off plays files by name.");
|
||||
MuteGameMusic = Config.Bind("Radio", "MuteGameMusic", true, "While the radio is on, mute the game's music buses. That includes the Dom bus track. Sound effects stay on.");
|
||||
MusicBusFilter = Config.Bind("Radio", "MusicBusFilter", "Music", "Mute FMOD buses whose path contains this text. Music covers the Dom bus home track.");
|
||||
Folder = Config.Bind("Radio", "Folder", "", "Folder of .mp3 and .wav files. Leave empty to use BepInEx/plugins/DomRadio/Music.");
|
||||
ShowNowPlaying = Config.Bind("Radio", "ShowNowPlaying", true, "Show the current file name while the radio is on.");
|
||||
|
||||
ClassInjector.RegisterTypeInIl2Cpp<DomRadioPlayer>();
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(MusicDirectory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.LogWarning("Could not create the music folder: " + ex.Message);
|
||||
}
|
||||
|
||||
_onPlayerStarted = DelegateSupport.ConvertDelegate<Il2CppSystem.Action<SkopjePlayer>>(new Action<SkopjePlayer>(OnPlayerStarted));
|
||||
_onPlayerStopped = DelegateSupport.ConvertDelegate<Il2CppSystem.Action<SkopjePlayer>>(new Action<SkopjePlayer>(OnPlayerStopped));
|
||||
ModAPI.add_OnPlayerStartedClient(_onPlayerStarted);
|
||||
ModAPI.add_OnPlayerStoppedClient(_onPlayerStopped);
|
||||
|
||||
_host = new GameObject("SkopjeDomRadio");
|
||||
UnityEngine.Object.DontDestroyOnLoad(_host);
|
||||
_host.hideFlags = HideFlags.HideAndDontSave;
|
||||
_host.AddComponent<DomRadioPlayer>();
|
||||
|
||||
Log.LogInfo($"{PluginName} {PluginVersion} loaded. Put .mp3 and .wav files in {MusicDirectory}. Toggle {Toggle.Value}, next {NextTrack.Value}, previous {PreviousTrack.Value}.");
|
||||
}
|
||||
|
||||
public override bool Unload()
|
||||
{
|
||||
if (DomRadioPlayer.Instance != null)
|
||||
DomRadioPlayer.Instance.TurnOff(false);
|
||||
GameMusic.Release();
|
||||
LocalPlayer = null;
|
||||
if (_onPlayerStarted != null)
|
||||
ModAPI.remove_OnPlayerStartedClient(_onPlayerStarted);
|
||||
if (_onPlayerStopped != null)
|
||||
ModAPI.remove_OnPlayerStoppedClient(_onPlayerStopped);
|
||||
if (_host != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(_host);
|
||||
_host = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static string MusicDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
string custom = Folder == null ? null : Folder.Value;
|
||||
if (!string.IsNullOrWhiteSpace(custom))
|
||||
return custom;
|
||||
return Path.Combine(Paths.PluginPath, "DomRadio", "Music");
|
||||
}
|
||||
}
|
||||
|
||||
static void OnPlayerStarted(SkopjePlayer player)
|
||||
{
|
||||
if (player != null && player.IsOwner)
|
||||
LocalPlayer = player;
|
||||
}
|
||||
|
||||
static void OnPlayerStopped(SkopjePlayer player)
|
||||
{
|
||||
if (LocalPlayer == player)
|
||||
LocalPlayer = null;
|
||||
}
|
||||
|
||||
internal static SkopjePlayer FindLocalPlayer()
|
||||
{
|
||||
if (LocalPlayer != null)
|
||||
return LocalPlayer;
|
||||
|
||||
var players = UnityEngine.Object.FindObjectsOfType<SkopjePlayer>();
|
||||
if (players == null)
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < players.Length; i++)
|
||||
{
|
||||
SkopjePlayer player = players[i];
|
||||
if (player != null && player.IsOwner)
|
||||
{
|
||||
LocalPlayer = player;
|
||||
return player;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static float MusicLevel()
|
||||
{
|
||||
try
|
||||
{
|
||||
OptionsManager manager = OptionsManager.Instance;
|
||||
if (manager == null || manager.OptionsData == null)
|
||||
return 1f;
|
||||
|
||||
return Unit(manager.OptionsData.MasterVolume) * Unit(manager.OptionsData.MusicVolume);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return 1f;
|
||||
}
|
||||
}
|
||||
|
||||
static float Unit(float value)
|
||||
{
|
||||
if (value > 1f)
|
||||
value *= 0.01f;
|
||||
return Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
public class DomRadioPlayer : MonoBehaviour
|
||||
{
|
||||
const float MissedPlaySeconds = 2f;
|
||||
|
||||
public static DomRadioPlayer Instance { get; private set; }
|
||||
|
||||
readonly List<string> _tracks = new List<string>();
|
||||
FMOD.Sound _sound;
|
||||
FMOD.Channel _channel;
|
||||
bool _hasSound;
|
||||
int _index;
|
||||
int _failures;
|
||||
bool _on;
|
||||
bool _suspended;
|
||||
bool _skipPending;
|
||||
bool _heardPlayback;
|
||||
bool _loggedEmpty;
|
||||
float _playDeadline;
|
||||
string _nowPlaying = string.Empty;
|
||||
string _notice = string.Empty;
|
||||
float _noticeUntil;
|
||||
GUIStyle _label;
|
||||
Texture2D _backdrop;
|
||||
int _styleHeight;
|
||||
|
||||
public DomRadioPlayer(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
TurnOff(false);
|
||||
if (_backdrop != null)
|
||||
Destroy(_backdrop);
|
||||
if (Instance == this)
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
bool inside = InDom();
|
||||
if (Pressed(DomRadioPlugin.Toggle.Value))
|
||||
{
|
||||
if (_on)
|
||||
TurnOff(true);
|
||||
else if (inside)
|
||||
TurnOn();
|
||||
else
|
||||
Notify("Radio only plays in the Dom", 2f);
|
||||
}
|
||||
|
||||
if (!_on)
|
||||
return;
|
||||
|
||||
if (!inside)
|
||||
{
|
||||
if (!_suspended)
|
||||
Suspend();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_suspended)
|
||||
Resume();
|
||||
|
||||
if (Pressed(DomRadioPlugin.NextTrack.Value))
|
||||
Advance(1);
|
||||
else if (Pressed(DomRadioPlugin.PreviousTrack.Value))
|
||||
Advance(-1);
|
||||
|
||||
PumpLoad();
|
||||
// Mute the Dom track only while one of our files is actually audible.
|
||||
if (DomRadioPlugin.MuteGameMusic.Value && IsAudible())
|
||||
GameMusic.Hold();
|
||||
else if (!DomRadioPlugin.MuteGameMusic.Value)
|
||||
GameMusic.Release();
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (Event.current == null || Event.current.type != EventType.Repaint || GUI.skin == null)
|
||||
return;
|
||||
|
||||
EnsureStyle();
|
||||
const float width = 640f;
|
||||
const float height = 36f;
|
||||
float textWidth = width - _label.padding.left - _label.padding.right;
|
||||
|
||||
string text = null;
|
||||
if (_on && !_suspended && DomRadioPlugin.ShowNowPlaying.Value && !string.IsNullOrEmpty(_nowPlaying))
|
||||
text = Fit(_nowPlaying, textWidth);
|
||||
else if (Time.unscaledTime <= _noticeUntil && !string.IsNullOrEmpty(_notice))
|
||||
text = Fit(_notice, textWidth);
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
var rect = new Rect((Screen.width - width) * 0.5f, Screen.height - 96f, width, height);
|
||||
Color previous = GUI.color;
|
||||
GUI.color = new Color(0f, 0f, 0f, 0.62f);
|
||||
GUI.DrawTexture(rect, _backdrop);
|
||||
GUI.color = previous;
|
||||
GUI.Label(rect, text, _label);
|
||||
}
|
||||
|
||||
public void TurnOn()
|
||||
{
|
||||
ReloadTracks();
|
||||
if (_tracks.Count == 0)
|
||||
{
|
||||
if (!_loggedEmpty)
|
||||
{
|
||||
_loggedEmpty = true;
|
||||
DomRadioPlugin.LogSource.LogInfo("Radio disabled. No .mp3 or .wav files in " + DomRadioPlugin.MusicDirectory + ". Dom music will keep playing.");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_loggedEmpty = false;
|
||||
_on = true;
|
||||
_failures = 0;
|
||||
_index = 0;
|
||||
_nowPlaying = TrackLabel(_tracks[0]);
|
||||
try
|
||||
{
|
||||
PlayFile(_tracks[0]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DomRadioPlugin.LogSource.LogWarning("Could not start the radio: " + ex.Message);
|
||||
TurnOff(false);
|
||||
DomRadioPlugin.LogSource.LogInfo("Radio disabled. Dom music restored.");
|
||||
return;
|
||||
}
|
||||
|
||||
DomRadioPlugin.LogSource.LogInfo("Radio on. " + _tracks.Count + " file(s) in " + DomRadioPlugin.MusicDirectory);
|
||||
}
|
||||
|
||||
public void TurnOff(bool announce)
|
||||
{
|
||||
_on = false;
|
||||
_suspended = false;
|
||||
_skipPending = false;
|
||||
_heardPlayback = false;
|
||||
_nowPlaying = string.Empty;
|
||||
StopSound();
|
||||
GameMusic.Release();
|
||||
if (announce)
|
||||
{
|
||||
Notify("Radio off", 2f);
|
||||
DomRadioPlugin.LogSource.LogInfo("Radio off. Dom music restored.");
|
||||
}
|
||||
}
|
||||
|
||||
void Advance(int direction)
|
||||
{
|
||||
if (_tracks.Count == 0)
|
||||
{
|
||||
TurnOff(true);
|
||||
return;
|
||||
}
|
||||
|
||||
int next = _index + direction;
|
||||
if (next >= _tracks.Count)
|
||||
next = 0;
|
||||
else if (next < 0)
|
||||
next = _tracks.Count - 1;
|
||||
|
||||
_index = next;
|
||||
_nowPlaying = TrackLabel(_tracks[_index]);
|
||||
PlayFile(_tracks[_index]);
|
||||
}
|
||||
|
||||
void ReloadTracks()
|
||||
{
|
||||
_tracks.Clear();
|
||||
string folder = DomRadioPlugin.MusicDirectory;
|
||||
if (!Directory.Exists(folder))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DomRadioPlugin.LogSource.LogWarning("Could not create the music folder: " + ex.Message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string[] files;
|
||||
try
|
||||
{
|
||||
files = Directory.GetFiles(folder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DomRadioPlugin.LogSource.LogWarning("Could not read the music folder: " + ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
string extension = Path.GetExtension(files[i]);
|
||||
if (extension.Equals(".mp3", StringComparison.OrdinalIgnoreCase) || extension.Equals(".wav", StringComparison.OrdinalIgnoreCase))
|
||||
_tracks.Add(files[i]);
|
||||
}
|
||||
|
||||
_tracks.Sort(StringComparer.OrdinalIgnoreCase);
|
||||
if (DomRadioPlugin.Shuffle.Value)
|
||||
ShuffleTracks();
|
||||
}
|
||||
|
||||
void ShuffleTracks()
|
||||
{
|
||||
var random = new System.Random();
|
||||
for (int i = _tracks.Count - 1; i > 0; i--)
|
||||
{
|
||||
int swap = random.Next(i + 1);
|
||||
string file = _tracks[i];
|
||||
_tracks[i] = _tracks[swap];
|
||||
_tracks[swap] = file;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayFile(string path)
|
||||
{
|
||||
StopSound();
|
||||
_heardPlayback = false;
|
||||
_nowPlaying = TrackLabel(path);
|
||||
if (!RuntimeManager.IsInitialized)
|
||||
{
|
||||
DomRadioPlugin.LogSource.LogWarning("Audio system is not ready yet.");
|
||||
_skipPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
FMOD.System core = RuntimeManager.CoreSystem;
|
||||
if (!core.hasHandle())
|
||||
{
|
||||
DomRadioPlugin.LogSource.LogWarning("Audio system is not ready yet.");
|
||||
_skipPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
FMOD.MODE mode = FMOD.MODE.CREATESTREAM | FMOD.MODE._2D | FMOD.MODE.LOOP_OFF;
|
||||
FMOD.Sound sound;
|
||||
FMOD.RESULT result = core.createSound(path, mode, out sound);
|
||||
if (result != FMOD.RESULT.OK || !sound.hasHandle())
|
||||
{
|
||||
DomRadioPlugin.LogSource.LogWarning("Could not open " + Path.GetFileName(path) + " (" + result + ").");
|
||||
_skipPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
FMOD.ChannelGroup master;
|
||||
core.getMasterChannelGroup(out master);
|
||||
FMOD.Channel channel;
|
||||
result = core.playSound(sound, master, false, out channel);
|
||||
if (result != FMOD.RESULT.OK || !channel.hasHandle())
|
||||
{
|
||||
sound.release();
|
||||
DomRadioPlugin.LogSource.LogWarning("Could not play " + Path.GetFileName(path) + " (" + result + ").");
|
||||
_skipPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
channel.setVolume(DomRadioPlugin.MusicLevel());
|
||||
_sound = sound;
|
||||
_channel = channel;
|
||||
_hasSound = true;
|
||||
_playDeadline = Time.unscaledTime + MissedPlaySeconds;
|
||||
}
|
||||
|
||||
void PumpLoad()
|
||||
{
|
||||
if (_skipPending)
|
||||
{
|
||||
_skipPending = false;
|
||||
OnTrackFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_hasSound)
|
||||
return;
|
||||
|
||||
if (IsAudible())
|
||||
{
|
||||
_heardPlayback = true;
|
||||
_failures = 0;
|
||||
_channel.setVolume(DomRadioPlugin.MusicLevel());
|
||||
return;
|
||||
}
|
||||
|
||||
if (_heardPlayback || Time.unscaledTime >= _playDeadline)
|
||||
Advance(1);
|
||||
}
|
||||
|
||||
bool IsAudible()
|
||||
{
|
||||
if (!_hasSound || !_channel.hasHandle())
|
||||
return false;
|
||||
bool playing = false;
|
||||
return _channel.isPlaying(out playing) == FMOD.RESULT.OK && playing;
|
||||
}
|
||||
|
||||
void OnTrackFailed()
|
||||
{
|
||||
_failures++;
|
||||
if (_tracks.Count == 0 || _failures >= _tracks.Count)
|
||||
{
|
||||
TurnOff(false);
|
||||
DomRadioPlugin.LogSource.LogInfo("Radio disabled. No playable files in " + DomRadioPlugin.MusicDirectory + ". Dom music restored.");
|
||||
return;
|
||||
}
|
||||
|
||||
Advance(1);
|
||||
}
|
||||
|
||||
void StopSound()
|
||||
{
|
||||
if (_hasSound && _channel.hasHandle())
|
||||
_channel.stop();
|
||||
if (_hasSound && _sound.hasHandle())
|
||||
_sound.release();
|
||||
_hasSound = false;
|
||||
}
|
||||
|
||||
void Notify(string text, float seconds)
|
||||
{
|
||||
_notice = text ?? string.Empty;
|
||||
_noticeUntil = Time.unscaledTime + seconds;
|
||||
}
|
||||
|
||||
static bool _loggedInput;
|
||||
|
||||
static bool Pressed(KeyCode key)
|
||||
{
|
||||
if (key == KeyCode.None)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
return Input.GetKeyDown(key);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!_loggedInput)
|
||||
{
|
||||
_loggedInput = true;
|
||||
DomRadioPlugin.LogSource.LogWarning("Keyboard input is unavailable: " + ex.Message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool InDom()
|
||||
{
|
||||
SkopjePlayer player = DomRadioPlugin.FindLocalPlayer();
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
return player.InsideVehicle != null;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
DomRadioPlugin.LocalPlayer = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Suspend()
|
||||
{
|
||||
_suspended = true;
|
||||
if (_hasSound && _channel.hasHandle())
|
||||
_channel.setPaused(true);
|
||||
GameMusic.Release();
|
||||
}
|
||||
|
||||
void Resume()
|
||||
{
|
||||
_suspended = false;
|
||||
if (_hasSound && _channel.hasHandle())
|
||||
{
|
||||
_channel.setPaused(false);
|
||||
_channel.setVolume(DomRadioPlugin.MusicLevel());
|
||||
return;
|
||||
}
|
||||
|
||||
if (_index >= 0 && _index < _tracks.Count)
|
||||
PlayFile(_tracks[_index]);
|
||||
}
|
||||
|
||||
string Fit(string text, float width)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text) || _label.CalcSize(new GUIContent(text)).x <= width)
|
||||
return text;
|
||||
|
||||
const string ellipsis = "...";
|
||||
int low = 0;
|
||||
int high = text.Length;
|
||||
while (low < high)
|
||||
{
|
||||
int mid = (low + high + 1) / 2;
|
||||
string candidate = text.Substring(0, mid).TrimEnd() + ellipsis;
|
||||
if (_label.CalcSize(new GUIContent(candidate)).x <= width)
|
||||
low = mid;
|
||||
else
|
||||
high = mid - 1;
|
||||
}
|
||||
|
||||
if (low <= 0)
|
||||
return ellipsis;
|
||||
return text.Substring(0, low).TrimEnd() + ellipsis;
|
||||
}
|
||||
|
||||
static string TrackLabel(string path)
|
||||
{
|
||||
return "Radio — " + Path.GetFileNameWithoutExtension(path);
|
||||
}
|
||||
|
||||
void EnsureStyle()
|
||||
{
|
||||
if (_backdrop == null)
|
||||
{
|
||||
_backdrop = new Texture2D(1, 1);
|
||||
_backdrop.SetPixel(0, 0, Color.white);
|
||||
_backdrop.Apply();
|
||||
}
|
||||
|
||||
if (_label != null && _styleHeight == Screen.height)
|
||||
return;
|
||||
|
||||
_styleHeight = Screen.height;
|
||||
_label = new GUIStyle(GUI.skin.label);
|
||||
_label.alignment = TextAnchor.MiddleCenter;
|
||||
_label.wordWrap = false;
|
||||
_label.clipping = TextClipping.Clip;
|
||||
_label.padding = new RectOffset(12, 12, 0, 0);
|
||||
_label.fontSize = Mathf.Clamp(Mathf.RoundToInt(Screen.height * 0.018f), 14, 28);
|
||||
_label.normal.textColor = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
// The Dom bus soundtrack is event:/Music/Bus/Home, on the game's Music buses.
|
||||
// Muting those buses leaves the events running, so the track returns when the radio turns off.
|
||||
static class GameMusic
|
||||
{
|
||||
sealed class HeldBus
|
||||
{
|
||||
public FMOD.Studio.Bus Bus;
|
||||
public bool WasMuted;
|
||||
}
|
||||
|
||||
static readonly List<HeldBus> _held = new List<HeldBus>();
|
||||
static bool _loggedMiss;
|
||||
static float _nextDiscover;
|
||||
|
||||
public static void Hold()
|
||||
{
|
||||
if (!DomRadioPlugin.MuteGameMusic.Value)
|
||||
return;
|
||||
if (!RuntimeManager.IsInitialized)
|
||||
return;
|
||||
|
||||
if (_held.Count == 0 && Time.unscaledTime >= _nextDiscover)
|
||||
{
|
||||
_nextDiscover = Time.unscaledTime + 1f;
|
||||
Discover();
|
||||
}
|
||||
|
||||
int valid = 0;
|
||||
for (int i = 0; i < _held.Count; i++)
|
||||
{
|
||||
FMOD.Studio.Bus bus = _held[i].Bus;
|
||||
if (!bus.isValid())
|
||||
continue;
|
||||
valid++;
|
||||
bus.setMute(true);
|
||||
}
|
||||
|
||||
// Banks reload with a new level. Drop dead handles so the next pass can find the music buses again.
|
||||
if (_held.Count > 0 && valid == 0)
|
||||
{
|
||||
_held.Clear();
|
||||
_nextDiscover = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Release()
|
||||
{
|
||||
for (int i = 0; i < _held.Count; i++)
|
||||
{
|
||||
FMOD.Studio.Bus bus = _held[i].Bus;
|
||||
if (bus.isValid())
|
||||
bus.setMute(_held[i].WasMuted);
|
||||
}
|
||||
|
||||
_held.Clear();
|
||||
_loggedMiss = false;
|
||||
_nextDiscover = 0f;
|
||||
}
|
||||
|
||||
static void Discover()
|
||||
{
|
||||
try
|
||||
{
|
||||
var studio = RuntimeManager.StudioSystem;
|
||||
if (!studio.isValid())
|
||||
return;
|
||||
|
||||
Il2CppStructArray<FMOD.Studio.Bank> banks = null;
|
||||
if (studio.getBankList(out banks) != FMOD.RESULT.OK || banks == null || banks.Length == 0)
|
||||
return;
|
||||
|
||||
string filter = DomRadioPlugin.MusicBusFilter.Value ?? string.Empty;
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var others = new List<string>();
|
||||
for (int i = 0; i < banks.Length; i++)
|
||||
{
|
||||
FMOD.Studio.Bank bank = banks[i];
|
||||
if (!bank.isValid())
|
||||
continue;
|
||||
|
||||
Il2CppStructArray<FMOD.Studio.Bus> buses = null;
|
||||
if (bank.getBusList(out buses) != FMOD.RESULT.OK || buses == null)
|
||||
continue;
|
||||
|
||||
for (int b = 0; b < buses.Length; b++)
|
||||
{
|
||||
FMOD.Studio.Bus bus = buses[b];
|
||||
if (!bus.isValid())
|
||||
continue;
|
||||
|
||||
string path = null;
|
||||
if (bus.getPath(out path) != FMOD.RESULT.OK || string.IsNullOrEmpty(path))
|
||||
continue;
|
||||
if (!seen.Add(path))
|
||||
continue;
|
||||
if (filter.Length == 0 || path.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0)
|
||||
{
|
||||
others.Add(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool wasMuted = false;
|
||||
bus.getMute(out wasMuted);
|
||||
_held.Add(new HeldBus { Bus = bus, WasMuted = wasMuted });
|
||||
DomRadioPlugin.LogSource.LogInfo("Muting " + path);
|
||||
}
|
||||
}
|
||||
|
||||
if (_held.Count == 0 && !_loggedMiss)
|
||||
{
|
||||
_loggedMiss = true;
|
||||
DomRadioPlugin.LogSource.LogWarning("No music bus matched \"" + filter + "\". Dom music will keep playing. Buses: " + string.Join(", ", others));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DomRadioPlugin.LogSource.LogWarning("Could not find the music buses: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>Skopje.DomRadio</AssemblyName>
|
||||
<RootNamespace>Skopje.DomRadio</RootNamespace>
|
||||
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
|
||||
<GameDir Condition="'$(GameDir)' == ''">D:\SteamLibrary\steamapps\common\Skopje83</GameDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="BepInEx.Core">
|
||||
<HintPath>$(GameDir)\BepInEx\core\BepInEx.Core.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx.Unity.IL2CPP">
|
||||
<HintPath>$(GameDir)\BepInEx\core\BepInEx.Unity.IL2CPP.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Il2CppInterop.Runtime">
|
||||
<HintPath>$(GameDir)\BepInEx\core\Il2CppInterop.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Il2Cppmscorlib">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\Il2Cppmscorlib.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="SkopjeAssembly">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\SkopjeAssembly.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="FishNet.Runtime">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\FishNet.Runtime.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Archon.SwissArmyLib">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\Archon.SwissArmyLib.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="FMODUnity">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\FMODUnity.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.IMGUIModule">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\UnityEngine.IMGUIModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TextRenderingModule">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputLegacyModule">
|
||||
<HintPath>$(GameDir)\BepInEx\interop\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v6.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v6.0": {
|
||||
"Skopje.DomRadio/1.0.0": {
|
||||
"runtime": {
|
||||
"Skopje.DomRadio.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Skopje.DomRadio/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"format": 1,
|
||||
"restore": {
|
||||
"c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj": {}
|
||||
},
|
||||
"projects": {
|
||||
"c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj",
|
||||
"projectName": "Skopje.DomRadio",
|
||||
"projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj",
|
||||
"packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget",
|
||||
"outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"configFilePaths": [
|
||||
"C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net6.0"
|
||||
],
|
||||
"sources": {
|
||||
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net6.0": {
|
||||
"framework": "net6.0",
|
||||
"targetAlias": "net6.0",
|
||||
"projectReferences": {}
|
||||
}
|
||||
},
|
||||
"warningProperties": {
|
||||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
},
|
||||
"restoreAuditProperties": {
|
||||
"enableAudit": "true",
|
||||
"auditLevel": "low",
|
||||
"auditMode": "direct"
|
||||
},
|
||||
"SdkAnalysisLevel": "10.0.300"
|
||||
},
|
||||
"frameworks": {
|
||||
"net6.0": {
|
||||
"framework": "net6.0",
|
||||
"targetAlias": "net6.0",
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
"net47",
|
||||
"net471",
|
||||
"net472",
|
||||
"net48",
|
||||
"net481"
|
||||
],
|
||||
"assetTargetFallback": true,
|
||||
"warn": true,
|
||||
"downloadDependencies": [
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.NETCore.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.WindowsDesktop.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
}
|
||||
],
|
||||
"frameworkReferences": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<SourceRoot Include="C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
|
||||
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Skopje.DomRadio")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Skopje.DomRadio")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Skopje.DomRadio")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
// Generated by the MSBuild WriteCodeFragment class.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
fb5aa0eaad5177616647c1fd58891f07eda98dfbaa1c7f1588f2c8bfe53d1402
|
||||
@@ -0,0 +1,18 @@
|
||||
is_global = true
|
||||
build_property.TargetFramework = net6.0
|
||||
build_property.TargetFrameworkIdentifier = .NETCoreApp
|
||||
build_property.TargetFrameworkVersion = v6.0
|
||||
build_property.TargetPlatformMinVersion =
|
||||
build_property.UsingMicrosoftNETSdkWeb =
|
||||
build_property.ProjectTypeGuids =
|
||||
build_property.InvariantGlobalization =
|
||||
build_property.PlatformNeutralAssembly =
|
||||
build_property.EnforceExtendedAnalyzerRules =
|
||||
build_property.EntryPointFilePath =
|
||||
build_property._SupportedPlatformList = Linux,macOS,Windows
|
||||
build_property.RootNamespace = Skopje.DomRadio
|
||||
build_property.ProjectDir = c:\Users\andre\Desktop\SkopjeMods\DomRadio\
|
||||
build_property.EnableComHosting =
|
||||
build_property.EnableGeneratedComInterfaceComImportInterop =
|
||||
build_property.EffectiveAnalysisLevelStyle = 6.0
|
||||
build_property.EnableCodeStyleSeverity =
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
081092add6543b8dcb5ec27e0ed95920f8750f6a3a0b82e5686acb95102220e9
|
||||
@@ -0,0 +1,12 @@
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.csproj.AssemblyReference.cache
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.GeneratedMSBuildEditorConfig.editorconfig
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.AssemblyInfoInputs.cache
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.AssemblyInfo.cs
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.csproj.CoreCompileInputs.cache
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\bin\Release\net6.0\Skopje.DomRadio.deps.json
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\bin\Release\net6.0\Skopje.DomRadio.dll
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\bin\Release\net6.0\Skopje.DomRadio.pdb
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\Skopje.DomRadio.dll
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\refint\Skopje.DomRadio.dll
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\Skopje.DomRadio.pdb
|
||||
c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\ref\Skopje.DomRadio.dll
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"version": 4,
|
||||
"targets": {
|
||||
"net6.0": {}
|
||||
},
|
||||
"libraries": {},
|
||||
"projectFileDependencyGroups": {
|
||||
"net6.0": []
|
||||
},
|
||||
"packageFolders": {
|
||||
"C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget": {}
|
||||
},
|
||||
"project": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj",
|
||||
"projectName": "Skopje.DomRadio",
|
||||
"projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj",
|
||||
"packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget",
|
||||
"outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"configFilePaths": [
|
||||
"C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net6.0"
|
||||
],
|
||||
"sources": {
|
||||
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net6.0": {
|
||||
"framework": "net6.0",
|
||||
"targetAlias": "net6.0",
|
||||
"projectReferences": {}
|
||||
}
|
||||
},
|
||||
"warningProperties": {
|
||||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
},
|
||||
"restoreAuditProperties": {
|
||||
"enableAudit": "true",
|
||||
"auditLevel": "low",
|
||||
"auditMode": "direct"
|
||||
},
|
||||
"SdkAnalysisLevel": "10.0.300"
|
||||
},
|
||||
"frameworks": {
|
||||
"net6.0": {
|
||||
"framework": "net6.0",
|
||||
"targetAlias": "net6.0",
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
"net47",
|
||||
"net471",
|
||||
"net472",
|
||||
"net48",
|
||||
"net481"
|
||||
],
|
||||
"assetTargetFallback": true,
|
||||
"warn": true,
|
||||
"downloadDependencies": [
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.NETCore.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.WindowsDesktop.App.Ref",
|
||||
"version": "[6.0.36, 6.0.36]"
|
||||
}
|
||||
],
|
||||
"frameworkReferences": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dgSpecHash": "3mbnNdPiqio=",
|
||||
"success": true,
|
||||
"projectFilePath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj",
|
||||
"expectedPackageFiles": [
|
||||
"C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.netcore.app.ref\\6.0.36\\microsoft.netcore.app.ref.6.0.36.nupkg.sha512",
|
||||
"C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.windowsdesktop.app.ref\\6.0.36\\microsoft.windowsdesktop.app.ref.6.0.36.nupkg.sha512",
|
||||
"C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.aspnetcore.app.ref\\6.0.36\\microsoft.aspnetcore.app.ref.6.0.36.nupkg.sha512"
|
||||
],
|
||||
"logs": []
|
||||
}
|
||||
Reference in new issue
Block a user