using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Newtonsoft.Json;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("HeimdallVoice")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6038451d89c7bb0324241a2c518aea9778756540")]
[assembly: AssemblyProduct("HeimdallVoice")]
[assembly: AssemblyTitle("HeimdallVoice")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace HeimdallVoice;
public static class ApiClient
{
private static string _baseUrl = "http://127.0.0.1:24600";
private static readonly HttpClient Http = new HttpClient
{
Timeout = TimeSpan.FromSeconds(3.0)
};
public static void Configure(string baseUrl)
{
_baseUrl = PluginSettings.NormalizeBaseUrl(baseUrl);
ManualLogSource log = HeimdallVoicePlugin.Log;
if (log != null)
{
log.LogInfo((object)("Bridge configurado para " + _baseUrl));
}
}
public static void SendZoneUpdate(string steamId, ZoneData zone)
{
SendRequestAsync(_baseUrl + "/move", steamId, zone?.name, null, zone?.discordChannelId);
}
public static void RestorePreviousChannel(string steamId)
{
SendRequestAsync(_baseUrl + "/restore", steamId, null);
}
public static void RegisterLinkCode(string steamId, string code)
{
SendRequestAsync(_baseUrl + "/register-link", steamId, null, code);
}
private static async Task SendRequestAsync(string url, string steamId, string zone, string code = null, string discordChannelId = null)
{
try
{
var payload = new { steamId, zone, code, discordChannelId };
string json = JsonConvert.SerializeObject((object)payload);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage response = await Http.PostAsync(url, (HttpContent)(object)content).ConfigureAwait(continueOnCapturedContext: false);
if (!response.IsSuccessStatusCode)
{
ManualLogSource log = HeimdallVoicePlugin.Log;
if (log != null)
{
log.LogError((object)$"Erro ao chamar API ({url}): {(int)response.StatusCode} {response.ReasonPhrase}");
}
return;
}
}
finally
{
((IDisposable)content)?.Dispose();
}
ManualLogSource log2 = HeimdallVoicePlugin.Log;
if (log2 != null)
{
log2.LogInfo((object)("API chamada com sucesso (" + url + ")"));
}
}
catch (Exception ex2)
{
Exception ex = ex2;
ManualLogSource log3 = HeimdallVoicePlugin.Log;
if (log3 != null)
{
log3.LogError((object)("Falha ao chamar API (" + url + "): " + ex.Message));
}
}
}
}
[BepInPlugin("heimdall.voice", "HeimdallVoice", "0.4.2")]
public class HeimdallVoicePlugin : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <ShowExtendedMessage>d__17 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public string message;
public HeimdallVoicePlugin <>4__this;
private int <i>5__1;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ShowExtendedMessage>d__17(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<i>5__1 = 0;
break;
case 1:
<>1__state = -1;
<i>5__1++;
break;
}
if (<i>5__1 < 3)
{
if ((Object)(object)Player.m_localPlayer == (Object)null)
{
return false;
}
((Character)Player.m_localPlayer).Message((MessageType)1, message, 0, (Sprite)null);
<>2__current = (object)new WaitForSeconds(1.8f);
<>1__state = 1;
return 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();
}
}
public static ManualLogSource Log;
public static HeimdallVoicePlugin Instance;
private ZoneManager _zoneManager;
private ZoneData _currentZone;
private float _checkTimer;
private LinkCodeManager _linkCodeManager;
private Harmony _harmony;
private string _clientId;
private PluginSettings _settings;
private void Awake()
{
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"HeimdallVoice initializing...");
_linkCodeManager = new LinkCodeManager();
_settings = PluginSettings.Bind(((BaseUnityPlugin)this).Config);
_zoneManager = new ZoneManager(((BaseUnityPlugin)this).Config);
_zoneManager.LoadZones();
ApiClient.Configure(_settings.BridgeBaseUrl);
_clientId = LoadOrCreateClientId();
RegisterCommands();
PatchChatVoiceCommand();
Log.LogInfo((object)"HeimdallVoice initialized.");
}
private void RegisterCommands()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Expected O, but got Unknown
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
new ConsoleCommand("voice", "Gera codigo de vinculo do Discord", (ConsoleEvent)delegate
{
HandleVoiceCommand();
}, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
Log.LogInfo((object)"Comando 'voice' registrado.");
}
private void PatchChatVoiceCommand()
{
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Expected O, but got Unknown
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Expected O, but got Unknown
try
{
Type type = AccessTools.TypeByName("Chat");
if (type == null)
{
Log.LogWarning((object)"Tipo Chat nao encontrado; /voice no chat nao foi habilitado.");
return;
}
MethodInfo methodInfo = AccessTools.Method(type, "InputText", (Type[])null, (Type[])null);
if (methodInfo == null)
{
Log.LogWarning((object)"Metodo Chat.InputText nao encontrado; /voice no chat nao foi habilitado.");
return;
}
_harmony = new Harmony("heimdall.voice.chat");
HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(HeimdallVoicePlugin), "ChatInputTextPrefix", (Type[])null, (Type[])null));
_harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"Comando /voice no chat habilitado.");
}
catch (Exception ex)
{
Log.LogError((object)("Falha ao habilitar /voice no chat: " + ex.Message));
}
}
private static bool ChatInputTextPrefix(object __instance)
{
try
{
if ((Object)(object)Instance == (Object)null)
{
return true;
}
string chatInputText = Instance.GetChatInputText(__instance);
if (string.IsNullOrWhiteSpace(chatInputText))
{
return true;
}
string text = chatInputText.Trim();
if (!text.Equals("/voice", StringComparison.OrdinalIgnoreCase))
{
return true;
}
Instance.HandleVoiceCommand();
Instance.ClearChatInputText(__instance);
return false;
}
catch (Exception ex)
{
ManualLogSource log = Log;
if (log != null)
{
log.LogError((object)("Erro no interceptador de /voice: " + ex.Message));
}
return true;
}
}
private string GetChatInputText(object chatInstance)
{
if (chatInstance == null)
{
return null;
}
Type type = chatInstance.GetType();
FieldInfo fieldInfo = AccessTools.Field(type, "m_input");
if (fieldInfo == null)
{
return null;
}
object value = fieldInfo.GetValue(chatInstance);
if (value == null)
{
return null;
}
PropertyInfo propertyInfo = AccessTools.Property(value.GetType(), "text");
if (propertyInfo != null)
{
return propertyInfo.GetValue(value, null) as string;
}
FieldInfo fieldInfo2 = AccessTools.Field(value.GetType(), "text");
if (fieldInfo2 != null)
{
return fieldInfo2.GetValue(value) as string;
}
return null;
}
private void ClearChatInputText(object chatInstance)
{
if (chatInstance == null)
{
return;
}
Type type = chatInstance.GetType();
object obj = AccessTools.Field(type, "m_input")?.GetValue(chatInstance);
if (obj != null)
{
PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), "text");
if (propertyInfo != null)
{
propertyInfo.SetValue(obj, string.Empty, null);
}
(AccessTools.Method(type, "Hide", (Type[])null, (Type[])null) ?? AccessTools.Method(type, "HideInput", (Type[])null, (Type[])null))?.Invoke(chatInstance, null);
}
}
private void HandleVoiceCommand()
{
if (string.IsNullOrEmpty(_clientId))
{
ShowInGame("[HeimdallVoice] ClientID invalido.", extendedTime: false);
return;
}
string text = _linkCodeManager.GenerateCode(_clientId);
ApiClient.RegisterLinkCode(_clientId, text);
string message = "[HeimdallVoice] Codigo: " + text + ". Use no Discord: !link " + text;
ShowInGame(message, extendedTime: true);
Log.LogInfo((object)("Codigo de vinculo gerado para " + _clientId + ": " + text));
}
private void ShowInGame(string message, bool extendedTime)
{
Log.LogInfo((object)message);
if (!((Object)(object)Player.m_localPlayer == (Object)null))
{
if (!extendedTime)
{
((Character)Player.m_localPlayer).Message((MessageType)1, message, 0, (Sprite)null);
}
else
{
((MonoBehaviour)this).StartCoroutine(ShowExtendedMessage(message));
}
}
}
[IteratorStateMachine(typeof(<ShowExtendedMessage>d__17))]
private IEnumerator ShowExtendedMessage(string message)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ShowExtendedMessage>d__17(0)
{
<>4__this = this,
message = message
};
}
private void Update()
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Player.m_localPlayer == (Object)null)
{
return;
}
_checkTimer += Time.deltaTime;
if (_checkTimer < 1f)
{
return;
}
_checkTimer = 0f;
if (string.IsNullOrEmpty(_clientId))
{
Log.LogWarning((object)"ClientID invalido.");
return;
}
Vector3 position = ((Component)Player.m_localPlayer).transform.position;
ZoneData zoneForPosition = _zoneManager.GetZoneForPosition(position);
if (zoneForPosition == null)
{
if (_currentZone != null)
{
Log.LogInfo((object)("Player saiu da zona " + _currentZone.name + "; restaurando canal anterior."));
_currentZone = null;
ApiClient.RestorePreviousChannel(_clientId);
}
}
else if (_currentZone == null || !(_currentZone.name == zoneForPosition.name))
{
_currentZone = zoneForPosition;
Log.LogInfo((object)("Player moved to zone " + zoneForPosition.name));
ApiClient.SendZoneUpdate(_clientId, zoneForPosition);
}
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
private string LoadOrCreateClientId()
{
try
{
string text = SystemInfo.deviceUniqueIdentifier?.Trim();
if (IsUsableDeviceId(text))
{
string text2 = HashClientId(text);
Log.LogInfo((object)("ClientID derivado do dispositivo: " + text2));
return text2;
}
string text3 = Path.Combine(Paths.ConfigPath, "HeimdallVoice");
string path = Path.Combine(text3, "client_id.txt");
if (File.Exists(path))
{
string text4 = File.ReadAllText(path).Trim();
if (!string.IsNullOrEmpty(text4))
{
Log.LogWarning((object)("ClientID em fallback local: " + text4));
return text4;
}
}
Directory.CreateDirectory(text3);
string text5 = Guid.NewGuid().ToString("N");
File.WriteAllText(path, text5);
Log.LogWarning((object)("DeviceUniqueIdentifier indisponivel; fallback gerado: " + text5));
return text5;
}
catch (Exception ex)
{
Log.LogError((object)("Falha ao carregar/gerar ClientID: " + ex.Message));
return null;
}
}
private static bool IsUsableDeviceId(string deviceId)
{
if (string.IsNullOrWhiteSpace(deviceId))
{
return false;
}
return !deviceId.Equals("n/a", StringComparison.OrdinalIgnoreCase);
}
private static string HashClientId(string value)
{
using SHA256 sHA = SHA256.Create();
byte[] bytes = Encoding.UTF8.GetBytes(value);
byte[] array = sHA.ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder(array.Length * 2);
byte[] array2 = array;
foreach (byte b in array2)
{
stringBuilder.Append(b.ToString("x2"));
}
return stringBuilder.ToString();
}
}
public class LinkCodeManager
{
private Dictionary<string, string> _activeCodes = new Dictionary<string, string>();
private Random _random = new Random();
public string GenerateCode(string steamId)
{
string text = _random.Next(100000, 999999).ToString();
_activeCodes[steamId] = text;
return text;
}
public string GetCode(string steamId)
{
if (_activeCodes.ContainsKey(steamId))
{
return _activeCodes[steamId];
}
return null;
}
}
public class LinkManager
{
private Dictionary<string, string> _links;
private string _filePath;
public LinkManager()
{
_filePath = Path.Combine(Paths.ConfigPath, "HeimdallVoice", "links.json");
Load();
}
private void Load()
{
if (!File.Exists(_filePath))
{
_links = new Dictionary<string, string>();
return;
}
string text = File.ReadAllText(_filePath);
_links = JsonConvert.DeserializeObject<Dictionary<string, string>>(text);
}
public string GetDiscordId(string steamId)
{
if (_links.ContainsKey(steamId))
{
return _links[steamId];
}
return null;
}
}
public class PluginSettings
{
private class LegacyPluginSettings
{
public string bridgeBaseUrl = "http://127.0.0.1:24600";
}
private class BridgeConfig
{
public string bridgeBaseUrl = "http://127.0.0.1:24600";
public string discordToken = "COLOQUE_O_TOKEN_DO_BOT";
public string guildId = "COLOQUE_O_ID_DO_SERVIDOR";
public string serverHost = "0.0.0.0";
public int serverPort = 24600;
}
private const string DefaultBridgeBaseUrl = "http://127.0.0.1:24600";
private const string DefaultDiscordToken = "COLOQUE_O_TOKEN_DO_BOT";
private const string DefaultGuildId = "COLOQUE_O_ID_DO_SERVIDOR";
private const string DefaultServerHost = "0.0.0.0";
private const int DefaultServerPort = 24600;
private ConfigEntry<string> _bridgeBaseUrl;
private ConfigEntry<string> _discordToken;
private ConfigEntry<string> _guildId;
private ConfigEntry<string> _serverHost;
private ConfigEntry<int> _serverPort;
private string _bridgeConfigPath;
private bool _isSynchronizing;
public string BridgeBaseUrl => NormalizeBaseUrl(_bridgeBaseUrl?.Value);
public static PluginSettings Bind(ConfigFile config)
{
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Expected O, but got Unknown
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Expected O, but got Unknown
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Expected O, but got Unknown
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Expected O, but got Unknown
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Expected O, but got Unknown
PluginSettings pluginSettings = new PluginSettings();
string text = LoadLegacyBridgeBaseUrl();
BridgeConfig bridgeConfig = LoadBridgeConfig();
pluginSettings._bridgeConfigPath = ResolveBridgeConfigPath();
pluginSettings._bridgeBaseUrl = config.Bind<string>("Bridge", "URL Base", string.IsNullOrWhiteSpace(text) ? NormalizeBaseUrl(bridgeConfig.bridgeBaseUrl) : text, new ConfigDescription("Endereco base da API do HeimdallVoice Bridge.", (AcceptableValueBase)null, Array.Empty<object>()));
pluginSettings._discordToken = config.Bind<string>("Bot do Discord", "Token do Bot", NormalizeText(bridgeConfig.discordToken, "COLOQUE_O_TOKEN_DO_BOT"), new ConfigDescription("Token do bot do Discord usado pelo HeimdallVoice Bridge.", (AcceptableValueBase)null, Array.Empty<object>()));
pluginSettings._guildId = config.Bind<string>("Servidor do Discord", "ID do Servidor", NormalizeText(bridgeConfig.guildId, "COLOQUE_O_ID_DO_SERVIDOR"), new ConfigDescription("ID do servidor (guild) do Discord.", (AcceptableValueBase)null, Array.Empty<object>()));
pluginSettings._serverHost = config.Bind<string>("Servidor da Bridge", "Host", NormalizeText(bridgeConfig.serverHost, "0.0.0.0"), new ConfigDescription("Host onde o HeimdallVoice Bridge vai escutar.", (AcceptableValueBase)null, Array.Empty<object>()));
pluginSettings._serverPort = config.Bind<int>("Servidor da Bridge", "Porta", NormalizePort(bridgeConfig.serverPort), new ConfigDescription("Porta onde o HeimdallVoice Bridge vai escutar.", (AcceptableValueBase)null, Array.Empty<object>()));
pluginSettings._bridgeBaseUrl.Value = NormalizeBaseUrl(pluginSettings._bridgeBaseUrl.Value);
pluginSettings._discordToken.Value = NormalizeText(pluginSettings._discordToken.Value, "COLOQUE_O_TOKEN_DO_BOT");
pluginSettings._guildId.Value = NormalizeText(pluginSettings._guildId.Value, "COLOQUE_O_ID_DO_SERVIDOR");
pluginSettings._serverHost.Value = NormalizeText(pluginSettings._serverHost.Value, "0.0.0.0");
pluginSettings._serverPort.Value = NormalizePort(pluginSettings._serverPort.Value);
pluginSettings._bridgeBaseUrl.SettingChanged += pluginSettings.HandleBridgeSettingChanged;
pluginSettings._discordToken.SettingChanged += pluginSettings.HandleBridgeSettingChanged;
pluginSettings._guildId.SettingChanged += pluginSettings.HandleBridgeSettingChanged;
pluginSettings._serverHost.SettingChanged += pluginSettings.HandleBridgeSettingChanged;
pluginSettings._serverPort.SettingChanged += pluginSettings.HandleBridgeSettingChanged;
pluginSettings.PersistBridgeConfig();
return pluginSettings;
}
private static string LoadLegacyBridgeBaseUrl()
{
string path = Path.Combine(Paths.ConfigPath, "HeimdallVoice");
string path2 = Path.Combine(path, "settings.json");
try
{
if (!File.Exists(path2))
{
return null;
}
string text = File.ReadAllText(path2);
return NormalizeBaseUrl(JsonConvert.DeserializeObject<LegacyPluginSettings>(text)?.bridgeBaseUrl);
}
catch (Exception ex)
{
ManualLogSource log = HeimdallVoicePlugin.Log;
if (log != null)
{
log.LogError((object)("Falha ao carregar settings.json legado: " + ex.Message));
}
return null;
}
}
public static string NormalizeBaseUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return "http://127.0.0.1:24600";
}
return url.Trim().TrimEnd(new char[1] { '/' });
}
private void HandleBridgeSettingChanged(object sender, EventArgs args)
{
if (_isSynchronizing)
{
return;
}
_isSynchronizing = true;
try
{
_bridgeBaseUrl.Value = NormalizeBaseUrl(_bridgeBaseUrl.Value);
_discordToken.Value = NormalizeText(_discordToken.Value, "COLOQUE_O_TOKEN_DO_BOT");
_guildId.Value = NormalizeText(_guildId.Value, "COLOQUE_O_ID_DO_SERVIDOR");
_serverHost.Value = NormalizeText(_serverHost.Value, "0.0.0.0");
_serverPort.Value = NormalizePort(_serverPort.Value);
ApiClient.Configure(_bridgeBaseUrl.Value);
PersistBridgeConfig();
}
finally
{
_isSynchronizing = false;
}
}
private void PersistBridgeConfig()
{
try
{
if (!string.IsNullOrWhiteSpace(_bridgeConfigPath))
{
string directoryName = Path.GetDirectoryName(_bridgeConfigPath);
if (!string.IsNullOrWhiteSpace(directoryName))
{
Directory.CreateDirectory(directoryName);
}
BridgeConfig bridgeConfig = new BridgeConfig
{
bridgeBaseUrl = NormalizeBaseUrl(_bridgeBaseUrl.Value),
discordToken = NormalizeText(_discordToken.Value, "COLOQUE_O_TOKEN_DO_BOT"),
guildId = NormalizeText(_guildId.Value, "COLOQUE_O_ID_DO_SERVIDOR"),
serverHost = NormalizeText(_serverHost.Value, "0.0.0.0"),
serverPort = NormalizePort(_serverPort.Value)
};
string contents = JsonConvert.SerializeObject((object)bridgeConfig, (Formatting)1);
File.WriteAllText(_bridgeConfigPath, contents);
}
}
catch (Exception ex)
{
ManualLogSource log = HeimdallVoicePlugin.Log;
if (log != null)
{
log.LogError((object)("Falha ao salvar config do bridge: " + ex.Message));
}
}
}
private static BridgeConfig LoadBridgeConfig()
{
string text = ResolveBridgeConfigPath();
BridgeConfig result = new BridgeConfig();
try
{
if (string.IsNullOrWhiteSpace(text) || !File.Exists(text))
{
return result;
}
string text2 = File.ReadAllText(text);
if (string.IsNullOrWhiteSpace(text2))
{
return result;
}
BridgeConfig bridgeConfig = JsonConvert.DeserializeObject<BridgeConfig>(text2) ?? new BridgeConfig();
bridgeConfig.bridgeBaseUrl = NormalizeBaseUrl(bridgeConfig.bridgeBaseUrl);
bridgeConfig.discordToken = NormalizeText(bridgeConfig.discordToken, "COLOQUE_O_TOKEN_DO_BOT");
bridgeConfig.guildId = NormalizeText(bridgeConfig.guildId, "COLOQUE_O_ID_DO_SERVIDOR");
bridgeConfig.serverHost = NormalizeText(bridgeConfig.serverHost, "0.0.0.0");
bridgeConfig.serverPort = NormalizePort(bridgeConfig.serverPort);
return bridgeConfig;
}
catch (Exception ex)
{
ManualLogSource log = HeimdallVoicePlugin.Log;
if (log != null)
{
log.LogError((object)("Falha ao carregar config do bridge: " + ex.Message));
}
return result;
}
}
private static string ResolveBridgeConfigPath()
{
try
{
string text = Directory.GetParent(Paths.BepInExRootPath)?.FullName;
if (!string.IsNullOrWhiteSpace(text))
{
return Path.Combine(text, "HeimdallVoice-Bridge", "config.json");
}
}
catch (Exception ex)
{
ManualLogSource log = HeimdallVoicePlugin.Log;
if (log != null)
{
log.LogWarning((object)("Nao foi possivel resolver o caminho do bridge: " + ex.Message));
}
}
return Path.Combine(Paths.ConfigPath, "HeimdallVoice", "bridge-config.json");
}
private static string NormalizeText(string value, string fallback)
{
return string.IsNullOrWhiteSpace(value) ? fallback : value.Trim();
}
private static int NormalizePort(int port)
{
return (port <= 0) ? 24600 : port;
}
}
public class ZoneManager
{
private const int MaxZoneSlots = 10;
private List<ZoneData> _zones = new List<ZoneData>();
private string _zoneFilePath;
private ConfigEntry<int> _zoneCount;
private readonly List<ZoneConfigEntrySet> _zoneEntries = new List<ZoneConfigEntrySet>();
private bool _isSynchronizing;
public ZoneManager(ConfigFile config)
{
_zoneFilePath = Path.Combine(Paths.ConfigPath, "HeimdallVoice", "zones.json");
BindConfig(config);
}
public void LoadZones()
{
ApplyConfigToRuntimeZones();
HeimdallVoicePlugin.Log.LogInfo((object)$"Loaded {_zones.Count} zones.");
}
public ZoneData GetZoneForPosition(Vector3 position)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
foreach (ZoneData zone in _zones)
{
float num = Vector2.Distance(new Vector2(position.x, position.z), new Vector2(zone.x, zone.z));
if (num <= zone.radius)
{
return zone;
}
}
return null;
}
private void CreateDefaultZonesFile()
{
Directory.CreateDirectory(Path.GetDirectoryName(_zoneFilePath));
List<ZoneData> list = CreateDefaultZones();
string contents = JsonConvert.SerializeObject((object)list, (Formatting)1);
File.WriteAllText(_zoneFilePath, contents);
}
private void BindConfig(ConfigFile config)
{
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Expected O, but got Unknown
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Expected O, but got Unknown
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Expected O, but got Unknown
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Expected O, but got Unknown
//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
//IL_01d0: Expected O, but got Unknown
List<ZoneData> list = LoadZonesFromDisk();
if (list.Count == 0)
{
CreateDefaultZonesFile();
HeimdallVoicePlugin.Log.LogWarning((object)"Zones file not found. Arquivo de exemplo criado.");
list = CreateDefaultZones();
}
_zoneCount = config.Bind<int>("Zonas", "Quantidade de Zonas", Mathf.Clamp(list.Count, 1, 10), new ConfigDescription($"Quantidade de zonas ativas exibidas abaixo. Maximo: {10}.", (AcceptableValueBase)null, Array.Empty<object>()));
_zoneCount.Value = Mathf.Clamp(_zoneCount.Value, 1, 10);
_zoneCount.SettingChanged += HandleZoneSettingsChanged;
for (int i = 0; i < 10; i++)
{
ZoneData zoneData = ((i < list.Count) ? list[i] : CreateDefaultZone(i + 1));
string text = $"Zona {i + 1}";
ZoneConfigEntrySet zoneConfigEntrySet = new ZoneConfigEntrySet
{
Name = config.Bind<string>(text, "Nome", NormalizeZoneName(zoneData.name, i + 1), new ConfigDescription("Nome da zona.", (AcceptableValueBase)null, Array.Empty<object>())),
X = config.Bind<float>(text, "Posicao X", zoneData.x, new ConfigDescription("Posicao X da zona no mapa.", (AcceptableValueBase)null, Array.Empty<object>())),
Z = config.Bind<float>(text, "Posicao Z", zoneData.z, new ConfigDescription("Posicao Z da zona no mapa.", (AcceptableValueBase)null, Array.Empty<object>())),
Radius = config.Bind<float>(text, "Raio", (zoneData.radius <= 0f) ? 60f : zoneData.radius, new ConfigDescription("Raio da zona.", (AcceptableValueBase)null, Array.Empty<object>())),
DiscordChannelId = config.Bind<string>(text, "ID da Sala Discord", NormalizeChannelId(zoneData.discordChannelId), new ConfigDescription("ID da sala de voz do Discord para esta zona.", (AcceptableValueBase)null, Array.Empty<object>()))
};
zoneConfigEntrySet.Name.SettingChanged += HandleZoneSettingsChanged;
zoneConfigEntrySet.X.SettingChanged += HandleZoneSettingsChanged;
zoneConfigEntrySet.Z.SettingChanged += HandleZoneSettingsChanged;
zoneConfigEntrySet.Radius.SettingChanged += HandleZoneSettingsChanged;
zoneConfigEntrySet.DiscordChannelId.SettingChanged += HandleZoneSettingsChanged;
_zoneEntries.Add(zoneConfigEntrySet);
}
PersistZonesFromConfig();
}
private void HandleZoneSettingsChanged(object sender, EventArgs args)
{
if (!_isSynchronizing)
{
PersistZonesFromConfig();
}
}
private void PersistZonesFromConfig()
{
_isSynchronizing = true;
try
{
_zoneCount.Value = Mathf.Clamp(_zoneCount.Value, 1, 10);
ApplyConfigToRuntimeZones();
Directory.CreateDirectory(Path.GetDirectoryName(_zoneFilePath));
string contents = JsonConvert.SerializeObject((object)_zones, (Formatting)1);
File.WriteAllText(_zoneFilePath, contents);
}
catch (Exception ex)
{
ManualLogSource log = HeimdallVoicePlugin.Log;
if (log != null)
{
log.LogError((object)("Falha ao salvar zonas: " + ex.Message));
}
}
finally
{
_isSynchronizing = false;
}
}
private void ApplyConfigToRuntimeZones()
{
List<ZoneData> list = new List<ZoneData>();
int num = Mathf.Clamp(_zoneCount?.Value ?? 1, 1, 10);
for (int i = 0; i < num && i < _zoneEntries.Count; i++)
{
ZoneConfigEntrySet zoneConfigEntrySet = _zoneEntries[i];
list.Add(new ZoneData
{
name = NormalizeZoneName(zoneConfigEntrySet.Name.Value, i + 1),
x = zoneConfigEntrySet.X.Value,
z = zoneConfigEntrySet.Z.Value,
radius = ((zoneConfigEntrySet.Radius.Value <= 0f) ? 60f : zoneConfigEntrySet.Radius.Value),
discordChannelId = NormalizeChannelId(zoneConfigEntrySet.DiscordChannelId.Value)
});
}
_zones = list;
}
private List<ZoneData> LoadZonesFromDisk()
{
try
{
if (!File.Exists(_zoneFilePath))
{
return new List<ZoneData>();
}
string text = File.ReadAllText(_zoneFilePath);
if (string.IsNullOrWhiteSpace(text))
{
return new List<ZoneData>();
}
return JsonConvert.DeserializeObject<List<ZoneData>>(text) ?? new List<ZoneData>();
}
catch (Exception ex)
{
ManualLogSource log = HeimdallVoicePlugin.Log;
if (log != null)
{
log.LogError((object)("Falha ao carregar zonas: " + ex.Message));
}
return new List<ZoneData>();
}
}
private static List<ZoneData> CreateDefaultZones()
{
return new List<ZoneData> { CreateDefaultZone(1) };
}
private static ZoneData CreateDefaultZone(int index)
{
return new ZoneData
{
name = ((index == 1) ? "Global" : $"Zone {index}"),
x = 0f,
z = 0f,
radius = 60f,
discordChannelId = "ID_DO_CANAL_DISCORD"
};
}
private static string NormalizeZoneName(string name, int index)
{
return string.IsNullOrWhiteSpace(name) ? $"Zone {index}" : name.Trim();
}
private static string NormalizeChannelId(string channelId)
{
return string.IsNullOrWhiteSpace(channelId) ? "ID_DO_CANAL_DISCORD" : channelId.Trim();
}
}
internal class ZoneConfigEntrySet
{
public ConfigEntry<string> Name;
public ConfigEntry<float> X;
public ConfigEntry<float> Z;
public ConfigEntry<float> Radius;
public ConfigEntry<string> DiscordChannelId;
}
public class ZoneData
{
public string name;
public float x;
public float z;
public float radius;
public string discordChannelId;
}