using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using Alpha;
using Alpha.Core.Command;
using Alpha.Core.Util;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Echo.Core;
using Echo.Core.Commands;
using Echo.Patches;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PurrNet;
using TMPro;
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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AndrewLin")]
[assembly: AssemblyConfiguration("Publish")]
[assembly: AssemblyDescription("Echo: A mod for On-Together with in-game utility commands including scheduled echoers (/echomein, /echolocalin, /echoglobalin), and more. Use /echohelp")]
[assembly: AssemblyFileVersion("0.2.5.0")]
[assembly: AssemblyInformationalVersion("0.2.5+4e0b7d4a1048390b61c91485bd217c1e7db83993")]
[assembly: AssemblyProduct("AndrewLin.Echo")]
[assembly: AssemblyTitle("AndrewLin.Echo")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/andrewlimforfun/ot-mods")]
[assembly: InternalsVisibleTo("Echo.Tests")]
[assembly: AssemblyVersion("0.2.5.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace Echo
{
public static class BuildInfo
{
public const string Version = "0.2.5";
}
[BepInPlugin("com.andrewlin.ontogether.echo", "Echo", "0.2.5")]
public class EchoPlugin : BaseUnityPlugin
{
public static readonly TokenValidator Validator = new TokenValidator("c7b7df644ec48a2ce66a51e05d084e177b0a01e6ecb77f9bd91808afe6668148");
private static ManualLogSource? _logger;
private static readonly ConcurrentQueue<Action> _mainThreadQueue = new ConcurrentQueue<Action>();
public const string ModGUID = "com.andrewlin.ontogether.echo";
public const string ModName = "Echo";
public const string ModVersion = "0.2.5";
private const string _locationsFileName = "com.andrewlin.ontogether.echo.locations.cfg";
public static ConfigEntry<bool>? EnableFeature { get; private set; }
public static ConfigEntry<string>? AccessToken { get; private set; }
public static SavedLocationManager? Locations { get; private set; }
public static void RunOnMainThread(Action action)
{
ConfigEntry<bool>? enableFeature = EnableFeature;
if (enableFeature != null && enableFeature.Value)
{
_mainThreadQueue.Enqueue(action);
}
}
private void Awake()
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Expected O, but got Unknown
_logger = ((BaseUnityPlugin)this).Logger;
((BaseUnityPlugin)this).Logger.LogInfo((object)"Echo v0.2.5 is loaded!");
InitConfig();
Locations = new SavedLocationManager(Path.Combine(Paths.ConfigPath, "com.andrewlin.ontogether.echo.locations.cfg"));
Harmony val = new Harmony("com.andrewlin.ontogether.echo");
val.PatchAll(typeof(PlayerMovementControllerPatch));
ChatCommandManager commandManager = AlphaPlugin.CommandManager;
if (commandManager != null)
{
commandManager.Register((IChatCommand)(object)new EchoToggleCommand());
}
ChatCommandManager commandManager2 = AlphaPlugin.CommandManager;
if (commandManager2 != null)
{
commandManager2.Register((IChatCommand)(object)new EchoTeleportPersonCommand());
}
ChatCommandManager commandManager3 = AlphaPlugin.CommandManager;
if (commandManager3 != null)
{
commandManager3.Register((IChatCommand)(object)new EchoTeleportLocationCommand());
}
ChatCommandManager commandManager4 = AlphaPlugin.CommandManager;
if (commandManager4 != null)
{
commandManager4.Register((IChatCommand)(object)new EchoLocationListCommand());
}
ChatCommandManager commandManager5 = AlphaPlugin.CommandManager;
if (commandManager5 != null)
{
commandManager5.Register((IChatCommand)(object)new EchoLocationRemoveCommand());
}
ChatCommandManager commandManager6 = AlphaPlugin.CommandManager;
if (commandManager6 != null)
{
commandManager6.Register((IChatCommand)(object)new EchoFollowCommand());
}
ChatCommandManager commandManager7 = AlphaPlugin.CommandManager;
if (commandManager7 != null)
{
commandManager7.Register((IChatCommand)(object)new EchoFollowRelativeCommand());
}
ChatCommandManager commandManager8 = AlphaPlugin.CommandManager;
if (commandManager8 != null)
{
commandManager8.Register((IChatCommand)(object)new EchoUnfollowCommand());
}
ChatCommandManager commandManager9 = AlphaPlugin.CommandManager;
if (commandManager9 != null)
{
commandManager9.Register((IChatCommand)(object)new EchoSyncRotationCommand());
}
ChatCommandManager commandManager10 = AlphaPlugin.CommandManager;
if (commandManager10 != null)
{
commandManager10.Register((IChatCommand)(object)new EchoUnsyncRotationCommand());
}
ChatCommandManager commandManager11 = AlphaPlugin.CommandManager;
if (commandManager11 != null)
{
commandManager11.Register((IChatCommand)(object)new EchoRotateCommand());
}
ChatCommandManager commandManager12 = AlphaPlugin.CommandManager;
if (commandManager12 != null)
{
commandManager12.Register((IChatCommand)(object)new EchoRotateLockCommand());
}
ChatCommandManager commandManager13 = AlphaPlugin.CommandManager;
if (commandManager13 != null)
{
commandManager13.Register((IChatCommand)(object)new EchoRotateUnlockCommand());
}
ChatCommandManager commandManager14 = AlphaPlugin.CommandManager;
if (commandManager14 != null)
{
commandManager14.Register((IChatCommand)(object)new EchoLookAtCommand());
}
ChatCommandManager commandManager15 = AlphaPlugin.CommandManager;
if (commandManager15 != null)
{
commandManager15.Register((IChatCommand)(object)new EchoCopyNameCommand());
}
ChatCommandManager commandManager16 = AlphaPlugin.CommandManager;
if (commandManager16 != null)
{
commandManager16.Register((IChatCommand)(object)new EchoCopyNameStyleCommand());
}
ChatCommandManager commandManager17 = AlphaPlugin.CommandManager;
if (commandManager17 != null)
{
commandManager17.Register((IChatCommand)(object)new EchoSetNameCommand());
}
ChatCommandManager commandManager18 = AlphaPlugin.CommandManager;
if (commandManager18 != null)
{
commandManager18.Register((IChatCommand)(object)new EchoGetNameCommand());
}
ChatCommandManager commandManager19 = AlphaPlugin.CommandManager;
if (commandManager19 != null)
{
commandManager19.Register((IChatCommand)(object)new EchoRevertNameCommand());
}
ChatCommandManager commandManager20 = AlphaPlugin.CommandManager;
if (commandManager20 != null)
{
commandManager20.Register((IChatCommand)(object)new EchoCopyOutfitCommand());
}
ChatCommandManager commandManager21 = AlphaPlugin.CommandManager;
if (commandManager21 != null)
{
commandManager21.Register((IChatCommand)(object)new EchoRemoveStatusCommand());
}
}
private void InitConfig()
{
EnableFeature = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableFeature", true, "Enable or disable the mod feature.");
AccessToken = ((BaseUnityPlugin)this).Config.Bind<string>("Security", "AccessToken", "put_the_secret_token_here", "Token required to use name/outfit copy commands. Must match the secret embedded in the mod.");
}
private void Update()
{
ConfigEntry<bool>? enableFeature = EnableFeature;
if (enableFeature == null || !enableFeature.Value)
{
return;
}
Action result;
while (_mainThreadQueue.TryDequeue(out result))
{
try
{
result();
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)("Main thread action failed: " + ex.Message));
}
}
}
private void OnDestroy()
{
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "AndrewLin.Echo";
public const string PLUGIN_NAME = "AndrewLin.Echo";
public const string PLUGIN_VERSION = "0.2.5";
}
}
namespace Echo.Patches
{
[HarmonyPatch(typeof(PlayerMovementController))]
public static class PlayerMovementControllerPatch
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.PlayerMovementControllerPatch");
public static Vector3 WarpPosition = Vector3.zero;
private static Transform? _followTarget;
private static Vector3 _followOffset;
private static bool _followRelative;
private static Transform? _rotationSyncTarget;
private static Transform? _lookAtTarget;
public static Quaternion? WarpRotation;
public static Quaternion? LockedRotation;
public static bool IsFollowing => (Object)(object)_followTarget != (Object)null;
public static bool IsSyncingRotation => (Object)(object)_rotationSyncTarget != (Object)null;
public static bool IsLookingAt => (Object)(object)_lookAtTarget != (Object)null;
public static void StartFollowing(Transform target, Vector3 offset, bool relative = false)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
_followTarget = target;
_followOffset = offset;
_followRelative = relative;
}
public static void StopFollowing()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
_followTarget = null;
_followOffset = Vector3.zero;
}
public static void StartSyncingRotation(Transform target)
{
_rotationSyncTarget = target;
}
public static void StopSyncingRotation()
{
_rotationSyncTarget = null;
}
public static void StartLookingAt(Transform target)
{
_lookAtTarget = target;
}
public static void StopLookingAt()
{
_lookAtTarget = null;
}
public static Vector3 GetLocalPlayerPosition()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: 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)
TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
return ((Object)(object)i != (Object)null) ? i.MainPlayer.position : Vector3.zero;
}
[HarmonyPrefix]
[HarmonyPatch("MovePlayer")]
public static bool MovePlayer_Prefix(ref CharacterController ____characterController, PlayerMovementController __instance)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
if ((Object)(object)i == (Object)null || (Object)(object)__instance != (Object)(object)i.MainMovementController)
{
return true;
}
if (WarpPosition != Vector3.zero)
{
if (IsFollowing)
{
StopFollowing();
ChatUtils.AddGlobalNotification("Stopped following (teleported).");
}
((Component)____characterController).transform.position = WarpPosition;
Logger.LogInfo((object)$"Teleported to {WarpPosition}");
WarpPosition = Vector3.zero;
return false;
}
if (WarpRotation.HasValue)
{
((Component)__instance).transform.rotation = WarpRotation.Value;
ManualLogSource logger = Logger;
Quaternion value = WarpRotation.Value;
logger.LogInfo((object)$"Rotated to {((Quaternion)(ref value)).eulerAngles}");
WarpRotation = null;
}
if (_followTarget != null && (Object)(object)_followTarget != (Object)null)
{
return false;
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch("Update")]
public static void Update_Postfix(PlayerMovementController __instance)
{
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
if (_followTarget == null && _rotationSyncTarget == null && _lookAtTarget == null && !LockedRotation.HasValue)
{
return;
}
TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
if ((Object)(object)i == (Object)null || (Object)(object)__instance != (Object)(object)i.MainMovementController)
{
return;
}
if (_followTarget != null)
{
if ((Object)(object)_followTarget == (Object)null || (Object)(object)((Component)_followTarget).gameObject == (Object)null || !((Component)_followTarget).gameObject.activeInHierarchy)
{
StopFollowing();
ChatUtils.AddGlobalNotification("Stopped following (target left).");
}
else
{
Vector3 val = (_followRelative ? (_followTarget.rotation * _followOffset) : _followOffset);
Vector3 position = _followTarget.position + val;
((Component)__instance).transform.position = position;
i.MainPlayer.position = position;
}
}
ApplyRotationSync(i.MainMovementController, __instance);
ApplyLookAt(i.MainMovementController, __instance);
if (LockedRotation.HasValue && (Object)(object)__instance == (Object)(object)i.MainMovementController)
{
((Component)__instance).transform.rotation = LockedRotation.Value;
}
}
private static void ApplyRotationSync(PlayerMovementController mainCtrl, PlayerMovementController instance)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
if (_rotationSyncTarget != null)
{
if ((Object)(object)_rotationSyncTarget == (Object)null || (Object)(object)((Component)_rotationSyncTarget).gameObject == (Object)null || !((Component)_rotationSyncTarget).gameObject.activeInHierarchy)
{
StopSyncingRotation();
ChatUtils.AddGlobalNotification("Stopped syncing rotation (target left).");
}
else if (!((Object)(object)instance != (Object)(object)mainCtrl))
{
float y = _rotationSyncTarget.eulerAngles.y;
((Component)instance).transform.rotation = Quaternion.Euler(0f, y, 0f);
}
}
}
private static void ApplyLookAt(PlayerMovementController mainCtrl, PlayerMovementController instance)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: 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)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
if (_lookAtTarget == null)
{
return;
}
if ((Object)(object)_lookAtTarget == (Object)null || (Object)(object)((Component)_lookAtTarget).gameObject == (Object)null || !((Component)_lookAtTarget).gameObject.activeInHierarchy)
{
StopLookingAt();
ChatUtils.AddGlobalNotification("Stopped looking at target (target left).");
}
else if (!((Object)(object)instance != (Object)(object)mainCtrl))
{
Vector3 val = _lookAtTarget.position - ((Component)instance).transform.position;
val.y = 0f;
if (!(((Vector3)(ref val)).sqrMagnitude < 0.01f))
{
((Component)instance).transform.rotation = Quaternion.LookRotation(val);
}
}
}
}
}
namespace Echo.Core
{
public class SavedLocationManager
{
private readonly string _filePath;
private readonly Dictionary<string, Vector3> _locations;
public SavedLocationManager(string filePath)
{
_filePath = filePath;
_locations = new Dictionary<string, Vector3>(StringComparer.OrdinalIgnoreCase);
Load();
}
public void Save(string name, Vector3 pos)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
_locations[name] = pos;
Persist();
}
public bool TryGet(string name, out Vector3 pos)
{
return _locations.TryGetValue(name, out pos);
}
public bool Delete(string name)
{
if (!_locations.Remove(name))
{
return false;
}
Persist();
return true;
}
public IReadOnlyDictionary<string, Vector3> GetAll()
{
return new ReadOnlyDictionary<string, Vector3>(_locations);
}
private void Load()
{
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
if (!File.Exists(_filePath))
{
return;
}
string[] array = File.ReadAllLines(_filePath);
foreach (string text in array)
{
int num = text.IndexOf('=');
if (num >= 1)
{
string key = text.Substring(0, num).Trim();
string[] array2 = text.Substring(num + 1).Split('|');
if (array2.Length == 3 && float.TryParse(array2[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
{
_locations[key] = new Vector3(result, result2, result3);
}
}
}
}
private void Persist()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
List<string> list = new List<string>();
foreach (KeyValuePair<string, Vector3> location in _locations)
{
string text = location.Value.x.ToString(CultureInfo.InvariantCulture);
string text2 = location.Value.y.ToString(CultureInfo.InvariantCulture);
string text3 = location.Value.z.ToString(CultureInfo.InvariantCulture);
list.Add(location.Key + "=" + text + "|" + text2 + "|" + text3);
}
File.WriteAllLines(_filePath, list);
}
}
public static class MoveUtil
{
public static bool IsRotationLocked => PlayerMovementControllerPatch.LockedRotation.HasValue;
public static void Teleport(Vector3 targetPosition)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
if ((Object)(object)i == (Object)null)
{
ChatUtils.AddGlobalNotification("Teleport failed: not in a session.");
return;
}
PlayerMovementControllerPatch.WarpPosition = targetPosition;
i.MainPlayer.position = targetPosition;
}
public static void SetRotation(float pitch, float yaw, float roll)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
PlayerMovementControllerPatch.WarpRotation = Quaternion.Euler(pitch, yaw, roll);
}
public static void LockRotation(float pitch, float yaw, float roll)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
PlayerMovementControllerPatch.LockedRotation = Quaternion.Euler(pitch, yaw, roll);
}
public static void UnlockRotation()
{
PlayerMovementControllerPatch.LockedRotation = null;
}
public static void LookAt(Vector3 targetPosition)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: 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)
Vector3 localPlayerPosition = PlayerMovementControllerPatch.GetLocalPlayerPosition();
Vector3 val = targetPosition - localPlayerPosition;
val.y = 0f;
if (!(((Vector3)(ref val)).sqrMagnitude < 0.01f))
{
PlayerMovementControllerPatch.WarpRotation = Quaternion.LookRotation(val);
}
}
}
internal static class NameStyleTransfer
{
internal readonly struct StyledSegment
{
public readonly string Tags;
public readonly string Text;
public StyledSegment(string tags, string text)
{
Tags = tags;
Text = text;
}
}
internal static List<StyledSegment> ParseSegments(string input)
{
List<StyledSegment> list = new List<StyledSegment>();
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder2 = new StringBuilder();
int num = 0;
while (num < input.Length)
{
if (input[num] == '<')
{
if (stringBuilder2.Length > 0)
{
list.Add(new StyledSegment(stringBuilder.ToString(), stringBuilder2.ToString()));
stringBuilder.Clear();
stringBuilder2.Clear();
}
int num2 = input.IndexOf('>', num);
if (num2 >= 0)
{
stringBuilder.Append(input, num, num2 - num + 1);
num = num2 + 1;
}
else
{
stringBuilder2.Append(input, num, input.Length - num);
num = input.Length;
}
}
else
{
stringBuilder2.Append(input[num]);
num++;
}
}
if (stringBuilder.Length > 0 || stringBuilder2.Length > 0)
{
list.Add(new StyledSegment(stringBuilder.ToString(), stringBuilder2.ToString()));
}
return list;
}
internal static string ApplyPositional(List<StyledSegment> segments, string myChars)
{
if (segments.Count == 0)
{
return myChars;
}
StringBuilder stringBuilder = new StringBuilder();
int num = 0;
for (int i = 0; i < segments.Count; i++)
{
stringBuilder.Append(segments[i].Tags);
int length = segments[i].Text.Length;
if (i == segments.Count - 1)
{
if (num < myChars.Length)
{
stringBuilder.Append(myChars, num, myChars.Length - num);
}
continue;
}
int num2 = Math.Min(num + length, myChars.Length);
if (num < num2)
{
stringBuilder.Append(myChars, num, num2 - num);
}
num = num2;
}
return stringBuilder.ToString();
}
internal static string ApplyEven(List<StyledSegment> segments, string myChars)
{
if (segments.Count == 0)
{
return myChars;
}
int num = 0;
foreach (StyledSegment segment in segments)
{
if (segment.Text.Length > 0)
{
num++;
}
}
if (num == 0)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (StyledSegment segment2 in segments)
{
stringBuilder.Append(segment2.Tags);
}
stringBuilder.Append(myChars);
return stringBuilder.ToString();
}
int num2 = myChars.Length / num;
int num3 = myChars.Length % num;
StringBuilder stringBuilder2 = new StringBuilder();
int num4 = 0;
int num5 = 0;
foreach (StyledSegment segment3 in segments)
{
stringBuilder2.Append(segment3.Tags);
if (segment3.Text.Length > 0)
{
int num6 = num2 + ((num5 < num3) ? 1 : 0);
int num7 = Math.Min(num4 + num6, myChars.Length);
if (num4 < num7)
{
stringBuilder2.Append(myChars, num4, num7 - num4);
}
num4 = num7;
num5++;
}
}
if (num4 < myChars.Length)
{
stringBuilder2.Append(myChars, num4, myChars.Length - num4);
}
return stringBuilder2.ToString();
}
internal static string ApplyEvenKeepNonAscii(List<StyledSegment> segments, string myChars)
{
if (segments.Count == 0)
{
return myChars;
}
int num = 0;
foreach (StyledSegment segment in segments)
{
string text = segment.Text;
foreach (char c in text)
{
if (c <= '\u007f')
{
num++;
}
}
}
if (num == 0)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (StyledSegment segment2 in segments)
{
stringBuilder.Append(segment2.Tags);
stringBuilder.Append(segment2.Text);
}
stringBuilder.Append(myChars);
return stringBuilder.ToString();
}
int num2 = 0;
foreach (StyledSegment segment3 in segments)
{
string text2 = segment3.Text;
foreach (char c2 in text2)
{
if (c2 <= '\u007f')
{
num2++;
break;
}
}
}
int num3 = myChars.Length / num2;
int num4 = myChars.Length % num2;
StringBuilder stringBuilder2 = new StringBuilder();
int num5 = 0;
int num6 = 0;
foreach (StyledSegment segment4 in segments)
{
stringBuilder2.Append(segment4.Tags);
bool flag = false;
string text3 = segment4.Text;
foreach (char c3 in text3)
{
if (c3 <= '\u007f')
{
flag = true;
break;
}
}
if (!flag)
{
stringBuilder2.Append(segment4.Text);
continue;
}
int num7 = num3 + ((num6 < num4) ? 1 : 0);
int l = 0;
string text4 = segment4.Text;
foreach (char c4 in text4)
{
if (c4 > '\u007f')
{
stringBuilder2.Append(c4);
}
else if (l < num7 && num5 < myChars.Length)
{
stringBuilder2.Append(myChars[num5]);
num5++;
l++;
}
}
for (; l < num7; l++)
{
if (num5 >= myChars.Length)
{
break;
}
stringBuilder2.Append(myChars[num5]);
num5++;
}
num6++;
}
if (num5 < myChars.Length)
{
stringBuilder2.Append(myChars, num5, myChars.Length - num5);
}
return stringBuilder2.ToString();
}
}
public static class NameUtil
{
private static readonly ManualLogSource _log = Logger.CreateLogSource("Echo.NU");
private const string OfficerBallsStatusManagerGUID = "officerballs.StatusManager";
public static string? OriginalName { get; private set; }
public static string GetName()
{
DataManager i = MonoSingleton<DataManager>.I;
if ((Object)(object)i == (Object)null)
{
_log.LogWarning((object)"GetName called before DataManager is available.");
return OriginalName ?? "Player";
}
return i.PlayerData.Name;
}
public static void SetName(string newName, bool saveOriginal = true)
{
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
DataManager i = MonoSingleton<DataManager>.I;
TextChannelManager i2 = NetworkSingleton<TextChannelManager>.I;
UIManager i3 = MonoSingleton<UIManager>.I;
MainSceneManager i4 = MonoSingleton<MainSceneManager>.I;
if ((Object)(object)i == (Object)null || (Object)(object)i2 == (Object)null)
{
_log.LogWarning((object)"SetName called before DataManager/TextChannelManager are available.");
return;
}
PluginInfo value;
if (saveOriginal && OriginalName == null)
{
string text = null;
if (Chainloader.PluginInfos.TryGetValue("officerballs.StatusManager", out value))
{
text = ((Chainloader.PluginInfos["officerballs.StatusManager"].Instance.Config["General", "PlayerName"] is ConfigEntry<string> val) ? val.Value : null);
}
if (!string.IsNullOrEmpty(text))
{
OriginalName = text;
}
else
{
OriginalName = i.PlayerData.Name;
}
}
i.PlayerData.Name = newName;
if ((Object)(object)i4 != (Object)null)
{
i2.MainCustomizationController.UpdatePlayerInfo(i.PlayerData.GetPlayerIdInfo(), default(RPCInfo));
((TMP_Text)i3.PlayerText).text = newName;
i2.UserName = newName;
if (Chainloader.PluginInfos.TryGetValue("officerballs.StatusManager", out value))
{
ChatUtils.UISendMessage("/setname " + newName);
}
}
_log.LogInfo((object)("Name set to: " + newName));
}
public static bool RevertName()
{
if (OriginalName == null)
{
return false;
}
string originalName = OriginalName;
OriginalName = null;
SetName(originalName, saveOriginal: false);
return true;
}
}
}
namespace Echo.Core.Commands
{
public class EchoCopyOutfitSelfCommand : IChatCommand, IComparable<IChatCommand>
{
private static ManualLogSource Logger = Logger.CreateLogSource("Echo.ECOSC");
public string Name => "echocopyoutfitself";
public string ShortName => "ecos";
public string Description => "Copy your current outfit/appearance to another slot. Usage: /echocopyoutfit <slot> (1-3)";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (args.Length != 1 || !int.TryParse(args[0], out var result) || result < 1 || result > 3)
{
ChatUtils.AddGlobalNotification("Usage: /echocopyoutfit <slot> (slot = 1, 2, or 3)");
return;
}
int num = result - 1;
DataManager i = MonoSingleton<DataManager>.I;
if ((Object)(object)i == (Object)null)
{
ChatUtils.AddGlobalNotification("DataManager not available.");
return;
}
PlayerDataZip playerDataZip = i.PlayerDataZip;
int selectedStyleIndex = playerDataZip.SelectedStyleIndex;
if (num == selectedStyleIndex)
{
ChatUtils.AddGlobalNotification($"Slot {result} is already your active slot - nothing to copy.");
return;
}
CustomizationDataIDs3 currentCustomizationDataIDs = playerDataZip.CurrentCustomizationDataIDs;
playerDataZip.SelectedStyleIndex = num;
playerDataZip.CurrentCustomizationDataIDs = currentCustomizationDataIDs;
playerDataZip.SelectedStyleIndex = selectedStyleIndex;
i.SavePlayerZipData();
string slotName = GetSlotName(playerDataZip, selectedStyleIndex);
string slotName2 = GetSlotName(playerDataZip, num);
Logger.LogInfo((object)$"Copied outfit from slot {selectedStyleIndex + 1} ({slotName}) to slot {result} ({slotName2}).");
ChatUtils.AddGlobalNotification($"Copied outfit from slot {selectedStyleIndex + 1} ({slotName}) → slot {result} ({slotName2}).");
}
private static string GetSlotName(PlayerDataZip pdz, int index)
{
if (pdz.StyleNames != null && index < pdz.StyleNames.Count)
{
return pdz.StyleNames[index];
}
return $"Slot {index + 1}";
}
}
public class EchoCopyNameCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource _log = Logger.CreateLogSource("Echo.ECONC");
public string Name => "echocopyname";
public string ShortName => "ecn";
public string Description => "Copy another player's display name (with TMP tags). Usage: /echocopyname <name|steamid_suffix|persona> [status_brackets]";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (!PlayerLists.IsAdmin(SteamUtils.GetPlayerSteamID()) && (EchoPlugin.AccessToken == null || !EchoPlugin.Validator.IsValid(EchoPlugin.AccessToken.Value.Trim())))
{
ChatUtils.AddGlobalNotification("Access denied: copy name has high abuse potential. Only Certified Users can use.");
return;
}
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /echocopyname <name|steamid_suffix|persona> [status_brackets]");
return;
}
string text = string.Join(" ", args).Trim();
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
string userName = val.UserName;
string text2 = ChatUtils.CleanTMPTags(userName).Trim();
_log.LogInfo((object)("Copying name from " + text2 + ": \"" + userName + "\""));
NameUtil.SetName(userName);
ChatUtils.AddGlobalNotification("Name copied from " + userName);
}
}
public class EchoCopyNameStyleCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.ECNSC");
public string Name => "echocopynamestyle";
public string ShortName => "ecns";
public string Description => "Copy another player's name styling onto your name. Usage: /ecns [-s] <player>. -s to also copy non-ASCII chars as style.";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (!PlayerLists.IsAdmin(SteamUtils.GetPlayerSteamID()) && (EchoPlugin.AccessToken == null || !EchoPlugin.Validator.IsValid(EchoPlugin.AccessToken.Value.Trim())))
{
ChatUtils.AddGlobalNotification("Access denied: copy name style has high abuse potential. Only Certified Users can use.");
return;
}
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /ecns [-s] <player>. -s to also copy non-ASCII chars as style.");
return;
}
bool flag = false;
int num = 0;
if (args[0].Equals("-s", StringComparison.OrdinalIgnoreCase))
{
flag = true;
num = 1;
}
if (num >= args.Length)
{
ChatUtils.AddGlobalNotification("Usage: /ecns [-s] <player>");
return;
}
string text = string.Join(" ", args, num, args.Length - num).Trim();
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
string userName = val.UserName;
string text2 = ChatUtils.CleanTMPTags(NameUtil.GetName()).Trim();
if (text2.Length == 0)
{
ChatUtils.AddGlobalNotification("Your name is empty after cleaning tags.");
return;
}
List<NameStyleTransfer.StyledSegment> segments = NameStyleTransfer.ParseSegments(userName);
string text3 = (flag ? NameStyleTransfer.ApplyEvenKeepNonAscii(segments, text2) : NameStyleTransfer.ApplyEven(segments, text2));
Logger.LogInfo((object)("Style copied from " + val.UserNameClean + ": \"" + text3 + "\""));
NameUtil.SetName(text3);
ChatUtils.AddGlobalNotification("Name style copied from " + val.UserNameClean + ".");
}
}
public class EchoCopyOutfitCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.ECOC");
private static readonly FieldInfo? CustomizationDataField = typeof(PlayerCustomizationController).GetField("_customizationData", BindingFlags.Instance | BindingFlags.NonPublic);
public string Name => "echocopyoutfit";
public string ShortName => "eco";
public string Description => "Copy another player's current outfit. Usage: /echocopyoutfit <name|steamid_suffix|persona>";
public string Namespace => "echo";
public void Execute(string[] args)
{
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Expected O, but got Unknown
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Expected O, but got Unknown
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Expected O, but got Unknown
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /echocopyoutfit <name|steamid_suffix|persona>");
return;
}
string text = string.Join(" ", args).Trim();
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
if (CustomizationDataField == null)
{
Logger.LogError((object)"Could not reflect _customizationData on PlayerCustomizationController.");
ChatUtils.AddGlobalNotification("Reflection error: outfit field not found.");
return;
}
PlayerCustomizationController component = ((Component)val.PlayerTransform).GetComponent<PlayerCustomizationController>();
if ((Object)(object)component == (Object)null)
{
ChatUtils.AddGlobalNotification("Could not find customization controller for " + ChatUtils.CleanTMPTags(val.UserName).Trim() + ".");
return;
}
CustomizationData val2 = (CustomizationData)CustomizationDataField.GetValue(component);
PlayerCustomizationController val3 = NetworkSingleton<TextChannelManager>.I?.MainCustomizationController;
if ((Object)(object)val3 == (Object)null)
{
ChatUtils.AddGlobalNotification("Local customization controller not available.");
return;
}
MonoSingleton<DataManager>.I.CustomizationData = new CustomizationData(val2);
MonoSingleton<DataManager>.I.PlayerDataZip.CurrentCustomizationDataIDs = new CustomizationDataIDs3(MonoSingleton<DataManager>.I.CustomizationData);
val3.ApplyCustomization(val2);
string text2 = ChatUtils.CleanTMPTags(val.UserName).Trim();
Logger.LogInfo((object)("Copied outfit from " + text2 + "."));
ChatUtils.AddGlobalNotification("Outfit copied from " + text2 + ".");
}
}
public class EchoFollowCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.EchoFollowCommand");
public string Name => "echofollow";
public string ShortName => "ef";
public string Description => "Follow a player at a fixed offset. Usage: /ef <name|steamid> [x y z]";
public string Namespace => "echo";
public void Execute(string[] args)
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /ef <name|steamid> [x y z]");
return;
}
Vector3? val = null;
string text;
if (args.Length >= 4 && float.TryParse(args[^3], out var result) && float.TryParse(args[^2], out var result2) && float.TryParse(args[^1], out var result3))
{
val = new Vector3(result, result2, result3);
text = string.Join(" ", args, 0, args.Length - 3);
}
else
{
text = string.Join(" ", args);
}
text = text.Trim();
PlayerDetail val2 = PlayerUtils.FindPlayerByQuery(text);
if (val2 == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
Vector3 localPlayerPosition = PlayerMovementControllerPatch.GetLocalPlayerPosition();
Vector3 val3 = (Vector3)(((??)val) ?? (localPlayerPosition - val2.Position));
string text2 = ChatUtils.CleanTMPTags(val2.UserName).Trim();
PlayerMovementControllerPatch.StartFollowing(((Component)val2.PlayerTransform).transform, val3);
Logger.LogInfo((object)$"Following {text2} at offset {val3}");
ChatUtils.AddGlobalNotification($"Following {text2} at offset ({val3.x:F1}, {val3.y:F1}, {val3.z:F1}). Use /eu to stop.");
}
}
public class EchoFollowRelativeCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.EchoFollowRelativeCommand");
private const float DefaultDistance = 1.5f;
public string Name => "echofollowrelative";
public string ShortName => "efr";
public string Description => "Follow a player relative to their facing. Usage: /efr <player> [behind|beside|front|x y z]";
public string Namespace => "echo";
public void Execute(string[] args)
{
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Unknown result type (might be due to invalid IL or missing references)
//IL_019f: Unknown result type (might be due to invalid IL or missing references)
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /efr <player> [behind|beside|front|x y z]");
return;
}
Vector3 offset = default(Vector3);
string text;
if (args.Length >= 4 && float.TryParse(args[^3], out var result) && float.TryParse(args[^2], out var result2) && float.TryParse(args[^1], out var result3))
{
((Vector3)(ref offset))..ctor(result, result2, result3);
text = string.Join(" ", args, 0, args.Length - 3).Trim();
}
else if (args.Length >= 2 && TryParsePreset(args[^1], out offset))
{
text = string.Join(" ", args, 0, args.Length - 1).Trim();
}
else
{
((Vector3)(ref offset))..ctor(0f, 0f, -1.5f);
text = string.Join(" ", args).Trim();
}
if (string.IsNullOrEmpty(text))
{
ChatUtils.AddGlobalNotification("Usage: /efr <player> [behind|beside|front|x y z]");
return;
}
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
string text2 = ChatUtils.CleanTMPTags(val.UserName).Trim();
PlayerMovementControllerPatch.StartFollowing(((Component)val.PlayerTransform).transform, offset, relative: true);
Logger.LogInfo((object)$"Following {text2} (relative) at offset {offset}");
ChatUtils.AddGlobalNotification($"Following {text2} (relative) at ({offset.x:F1}, {offset.y:F1}, {offset.z:F1}). Use /eu to stop.");
}
private static bool TryParsePreset(string s, out Vector3 offset)
{
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
switch (s.ToLowerInvariant())
{
case "behind":
case "back":
offset = new Vector3(0f, 0f, -1.5f);
return true;
case "beside":
case "left":
offset = new Vector3(-1.5f, 0f, 0f);
return true;
case "right":
offset = new Vector3(1.5f, 0f, 0f);
return true;
case "front":
case "ahead":
offset = new Vector3(0f, 0f, 1.5f);
return true;
default:
offset = Vector3.zero;
return false;
}
}
}
public class EchoGetNameCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource _log = Logger.CreateLogSource("Echo.ECONC");
public string Name => "echogetname";
public string ShortName => "egn";
public string Description => "Copy another player's display name (with TMP tags). Usage: /echogetname <name|steamid_suffix|persona> [status_brackets]";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (!PlayerLists.IsAdmin(SteamUtils.GetPlayerSteamID()) && (EchoPlugin.AccessToken == null || !EchoPlugin.Validator.IsValid(EchoPlugin.AccessToken.Value.Trim())))
{
ChatUtils.AddGlobalNotification("Access denied: get name has high abuse potential. Only Certified Users can use.");
return;
}
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /echogetname <name|steamid_suffix|persona> [status_brackets]");
return;
}
string text = string.Join(" ", args).Trim();
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
string userName = val.UserName;
string userNameClean = val.UserNameClean;
_log.LogInfo((object)("Name of " + userNameClean + ": \"" + userName + "\""));
ChatUtils.AddGlobalNotification("Name of " + userNameClean + ": " + userName);
}
}
public class EchoLocationListCommand : IChatCommand, IComparable<IChatCommand>
{
public string Name => "echolocationlist";
public string ShortName => "ell";
public string Description => "List all saved locations and their coordinates. Usage: /echolocationlist";
public string Namespace => "echo";
public void Execute(string[] args)
{
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
SavedLocationManager locations = EchoPlugin.Locations;
if (locations == null)
{
ChatUtils.AddGlobalNotification("Location manager not initialized.");
return;
}
IReadOnlyDictionary<string, Vector3> all = locations.GetAll();
if (all.Count == 0)
{
ChatUtils.AddGlobalNotification("No saved locations.");
return;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Saved locations ({all.Count}):");
foreach (KeyValuePair<string, Vector3> item in all)
{
stringBuilder.AppendLine($" {item.Key}: ({item.Value.x:F1}, {item.Value.y:F1}, {item.Value.z:F1})");
}
ChatUtils.AddGlobalNotification(stringBuilder.ToString().TrimEnd());
}
}
public class EchoLocationRemoveCommand : IChatCommand, IComparable<IChatCommand>
{
public string Name => "echolocationremove";
public string ShortName => "elr";
public string Description => "Remove a saved location. Usage: /echolocationremove <name>";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /echolocationremove <name>");
return;
}
SavedLocationManager locations = EchoPlugin.Locations;
if (locations == null)
{
ChatUtils.AddGlobalNotification("Location manager not initialized.");
return;
}
string text = string.Join(" ", args).Trim();
if (locations.Delete(text))
{
ChatUtils.AddGlobalNotification("Removed location \"" + text + "\".");
}
else
{
ChatUtils.AddGlobalNotification("No saved location named \"" + text + "\".");
}
}
}
public class EchoLookAtCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.EchoLookAtCommand");
public string Name => "echolookat";
public string ShortName => "ela";
public string Description => "Continuously face toward a player. Usage: /ela <name|steamid>. Stop with /eru.";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /ela <name|steamid>. Stop with /eru.");
return;
}
string text = string.Join(" ", args).Trim();
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
string text2 = ChatUtils.CleanTMPTags(val.UserName).Trim();
PlayerMovementControllerPatch.StartLookingAt(((Component)val.PlayerTransform).transform);
Logger.LogInfo((object)("Looking at " + text2 + "."));
ChatUtils.AddGlobalNotification("Facing toward " + text2 + ". Use /eru to stop.");
}
}
public class EchoRemoveStatusCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource _log = Logger.CreateLogSource("Echo.ERSC");
public string Name => "echoremovestatus";
public string ShortName => "ers";
public string Description => "Remove status from my player's display name. Usage: /echoremovestatus <status_brackets>";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (EchoPlugin.AccessToken == null || !EchoPlugin.Validator.IsValid(EchoPlugin.AccessToken.Value.Trim()))
{
ChatUtils.AddGlobalNotification("Access denied: remove status has high abuse potential. Only Certified Users can use.");
return;
}
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /echoremovestatus <status_brackets>");
return;
}
if (args.Length == 2)
{
ChatUtils.AddGlobalNotification("Please provide only one argument with the brackets to remove. Usage: /echoremovestatus <status_brackets>");
return;
}
string text = args[0].Trim();
string text2 = NameUtil.GetName();
if (text.Length == 1)
{
text2 = text2[..text2.LastIndexOf(text[0])];
}
else if (text.Length > 1)
{
char bracketStart = text[0];
char bracketEnd = text[text.Length - 1];
text2 = RemoveLastBracketedSection(text2, bracketStart, bracketEnd);
}
NameUtil.SetName(text2, saveOriginal: false);
ChatUtils.AddGlobalNotification("Status removed from " + text2);
}
public static string RemoveLastBracketedSection(string name, char bracketStart, char bracketEnd)
{
int num = name.LastIndexOf(bracketEnd);
if (num == -1)
{
return name;
}
int num2 = name.LastIndexOf(bracketStart, num);
if (num2 == -1)
{
return name;
}
return name.Remove(num2, num - num2 + 1).TrimEnd();
}
}
public class EchoRevertNameCommand : IChatCommand, IComparable<IChatCommand>
{
public string Name => "echorevertname";
public string ShortName => "ern";
public string Description => "Revert your display name to the original before any Echo rename.";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (NameUtil.OriginalName == null)
{
ChatUtils.AddGlobalNotification("No saved name to revert to.");
return;
}
string originalName = NameUtil.OriginalName;
NameUtil.RevertName();
string text = ChatUtils.CleanTMPTags(originalName).Trim();
ChatUtils.AddGlobalNotification("Name reverted to: " + text);
}
}
public class EchoRotateCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.EchoRotateCommand");
public string Name => "echorotate";
public string ShortName => "er";
public string Description => "Set facing direction. Usage: /er <degrees|pitch yaw roll|cardinal|player>";
public string Namespace => "echo";
public void Execute(string[] args)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
if (args.Length == 0)
{
PlayerDetail playerDetail = PlayerUtils.GetPlayerDetail();
Vector3 val = ((playerDetail != null) ? ((Component)playerDetail.PlayerTransform).transform.eulerAngles : Vector3.zero);
ChatUtils.AddGlobalNotification($"Current rotation: ({val.x:F1}, {val.y:F1}, {val.z:F1})");
return;
}
if (args.Length == 3 && float.TryParse(args[0], out var result) && float.TryParse(args[1], out var result2) && float.TryParse(args[2], out var result3))
{
MoveUtil.SetRotation(result, result2, result3);
ChatUtils.AddGlobalNotification($"Rotation set to ({result}, {result2}, {result3}).");
Logger.LogInfo((object)$"One-shot rotation to ({result}, {result2}, {result3}).");
return;
}
string text = string.Join(" ", args).Trim();
if (TryParseCardinal(text, out var angle))
{
MoveUtil.SetRotation(0f, angle, 0f);
ChatUtils.AddGlobalNotification($"Facing {text} ({angle} degrees).");
Logger.LogInfo((object)$"One-shot rotation to cardinal {text} ({angle}).");
return;
}
if (float.TryParse(text, out var result4))
{
MoveUtil.SetRotation(0f, result4, 0f);
ChatUtils.AddGlobalNotification($"Facing {result4} degrees.");
Logger.LogInfo((object)$"One-shot rotation to yaw {result4}.");
return;
}
PlayerDetail val2 = PlayerUtils.FindPlayerByQuery(text);
if (val2 != null)
{
MoveUtil.LookAt(((Component)val2.PlayerTransform).transform.position);
string text2 = ChatUtils.CleanTMPTags(val2.UserName).Trim();
ChatUtils.AddGlobalNotification("Facing toward " + text2 + ".");
Logger.LogInfo((object)("One-shot rotation toward player " + text2 + "."));
}
else
{
ChatUtils.AddGlobalNotification("Unknown target \"" + text + "\". Use degrees, cardinal, or player name.");
}
}
private static bool TryParseCardinal(string s, out float angle)
{
string text = s.ToLowerInvariant();
if (1 == 0)
{
}
float num = text switch
{
"north" => 0f,
"n" => 0f,
"east" => 90f,
"e" => 90f,
"south" => 180f,
"s" => 180f,
"west" => 270f,
"w" => 270f,
"northeast" => 45f,
"ne" => 45f,
"southeast" => 135f,
"se" => 135f,
"southwest" => 225f,
"sw" => 225f,
"northwest" => 315f,
"nw" => 315f,
_ => -1f,
};
if (1 == 0)
{
}
angle = num;
return angle >= 0f;
}
}
public class EchoRotateLockCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.EchoRotateLockCommand");
public string Name => "echorotatelock";
public string ShortName => "erl";
public string Description => "Lock rotation to a fixed value. Usage: /erl <degrees|pitch yaw roll|cardinal|player>. Unlock with /eru.";
public string Namespace => "echo";
public void Execute(string[] args)
{
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
//IL_01db: Unknown result type (might be due to invalid IL or missing references)
//IL_01df: Unknown result type (might be due to invalid IL or missing references)
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /erl <degrees|pitch yaw roll|cardinal|player>. Unlock with /eru.");
return;
}
if (args.Length == 3 && float.TryParse(args[0], out var result) && float.TryParse(args[1], out var result2) && float.TryParse(args[2], out var result3))
{
MoveUtil.LockRotation(result, result2, result3);
ChatUtils.AddGlobalNotification($"Rotation locked to ({result}, {result2}, {result3}). Use /eru to unlock.");
Logger.LogInfo((object)$"Rotation locked to ({result}, {result2}, {result3}).");
return;
}
string text = string.Join(" ", args).Trim();
if (TryParseCardinal(text, out var angle))
{
MoveUtil.LockRotation(0f, angle, 0f);
ChatUtils.AddGlobalNotification($"Rotation locked to {text} ({angle} degrees). Use /eru to unlock.");
Logger.LogInfo((object)$"Rotation locked to cardinal {text} ({angle}).");
return;
}
if (float.TryParse(text, out var result4))
{
MoveUtil.LockRotation(0f, result4, 0f);
ChatUtils.AddGlobalNotification($"Rotation locked to {result4} degrees. Use /eru to unlock.");
Logger.LogInfo((object)$"Rotation locked to yaw {result4}.");
return;
}
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val != null)
{
Vector3 localPlayerPosition = PlayerMovementControllerPatch.GetLocalPlayerPosition();
Vector3 val2 = ((Component)val.PlayerTransform).transform.position - localPlayerPosition;
val2.y = 0f;
if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
{
ChatUtils.AddGlobalNotification("Too close to target to determine direction.");
return;
}
Quaternion val3 = Quaternion.LookRotation(val2);
Vector3 eulerAngles = ((Quaternion)(ref val3)).eulerAngles;
MoveUtil.LockRotation(eulerAngles.x, eulerAngles.y, eulerAngles.z);
string text2 = ChatUtils.CleanTMPTags(val.UserName).Trim();
ChatUtils.AddGlobalNotification("Rotation locked toward " + text2 + ". Use /eru to unlock.");
Logger.LogInfo((object)("Rotation locked toward player " + text2 + "."));
}
else
{
ChatUtils.AddGlobalNotification("Unknown target \"" + text + "\". Use degrees, cardinal, or player name.");
}
}
private static bool TryParseCardinal(string s, out float angle)
{
string text = s.ToLowerInvariant();
if (1 == 0)
{
}
float num = text switch
{
"north" => 0f,
"n" => 0f,
"east" => 90f,
"e" => 90f,
"south" => 180f,
"s" => 180f,
"west" => 270f,
"w" => 270f,
"northeast" => 45f,
"ne" => 45f,
"southeast" => 135f,
"se" => 135f,
"southwest" => 225f,
"sw" => 225f,
"northwest" => 315f,
"nw" => 315f,
_ => -1f,
};
if (1 == 0)
{
}
angle = num;
return angle >= 0f;
}
}
public class EchoRotateUnlockCommand : IChatCommand, IComparable<IChatCommand>
{
public string Name => "echorotateunlock";
public string ShortName => "eru";
public string Description => "Stop all rotation overrides (lock, look-at).";
public string Namespace => "echo";
public void Execute(string[] args)
{
bool isRotationLocked = MoveUtil.IsRotationLocked;
bool isLookingAt = PlayerMovementControllerPatch.IsLookingAt;
if (!isRotationLocked && !isLookingAt)
{
ChatUtils.AddGlobalNotification("No rotation override active.");
return;
}
MoveUtil.UnlockRotation();
PlayerMovementControllerPatch.StopLookingAt();
ChatUtils.AddGlobalNotification("Rotation unlocked.");
}
}
public class EchoSetNameCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.EchoSetNameCommand");
public string Name => "echosetname";
public string ShortName => "esn";
public string Description => "Change name text while keeping current style. Usage: /esn <new name>";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /esn <new name>");
return;
}
string text = string.Join(" ", args).Trim();
if (text.Length == 0)
{
ChatUtils.AddGlobalNotification("Name cannot be empty.");
return;
}
string name = NameUtil.GetName();
List<NameStyleTransfer.StyledSegment> list = NameStyleTransfer.ParseSegments(name);
bool flag = false;
foreach (NameStyleTransfer.StyledSegment item in list)
{
if (item.Tags.Length > 0)
{
flag = true;
break;
}
}
string text2 = (flag ? NameStyleTransfer.ApplyEven(list, text) : text);
Logger.LogInfo((object)("Set name to \"" + text2 + "\" (preserving style)."));
NameUtil.SetName(text2);
ChatUtils.AddGlobalNotification("Name set to \"" + ChatUtils.CleanTMPTags(text2) + "\" with existing style.");
}
}
public class EchoSyncRotationCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.EchoSyncRotationCommand");
public string Name => "echosyncrotation";
public string ShortName => "esr";
public string Description => "Mirror another player's facing direction. Usage: /esr <name|steamid>. Stop with /eur.";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /esr <name|steamid>. Stop with /eur.");
return;
}
string text = string.Join(" ", args).Trim();
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
string text2 = ChatUtils.CleanTMPTags(val.UserName).Trim();
PlayerMovementControllerPatch.StartSyncingRotation(((Component)val.PlayerTransform).transform);
Logger.LogInfo((object)("Syncing rotation to " + text2 + "."));
ChatUtils.AddGlobalNotification("Syncing rotation to " + text2 + ". Use /eur to stop.");
}
}
public class EchoTeleportLocationCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource _log = Logger.CreateLogSource("Echo.ETL");
public string Name => "echoteleportlocation";
public string ShortName => "etl";
public string Description => "Teleport to a saved location or save current spot. Usage: /etl <name> | /etl <x> <y> <z>";
public string Namespace => "echo";
public void Execute(string[] args)
{
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /etl <name> - teleport to or save a location\n /etl <x> <y> <z> - teleport to coordinates");
return;
}
if (args.Length == 3 && float.TryParse(args[0], out var result) && float.TryParse(args[1], out var result2) && float.TryParse(args[2], out var result3))
{
Vector3 targetPosition = default(Vector3);
((Vector3)(ref targetPosition))..ctor(result, result2, result3);
MoveUtil.Teleport(targetPosition);
ChatUtils.AddGlobalNotification($"Teleported to ({result}, {result2}, {result3}).");
_log.LogInfo((object)$"Teleported to coordinates ({result}, {result2}, {result3}).");
return;
}
string text = string.Join(" ", args).Trim();
SavedLocationManager locations = EchoPlugin.Locations;
Vector3 pos;
if (locations == null)
{
ChatUtils.AddGlobalNotification("Location manager not initialized.");
}
else if (locations.TryGet(text, out pos))
{
MoveUtil.Teleport(pos);
ChatUtils.AddGlobalNotification("Teleported to \"" + text + "\".");
_log.LogInfo((object)$"Teleported to saved location \"{text}\" at {pos}.");
}
else
{
PlayerDetail playerDetail = PlayerUtils.GetPlayerDetail();
Vector3 val = ((playerDetail != null) ? playerDetail.Position : Vector3.zero);
locations.Save(text, val);
ChatUtils.AddGlobalNotification($"Saved location \"{text}\" at {val}.");
_log.LogInfo((object)$"Saved location \"{text}\" at {val}.");
}
}
}
public class EchoTeleportPersonCommand : IChatCommand, IComparable<IChatCommand>
{
private static readonly ManualLogSource Logger = Logger.CreateLogSource("Echo.EchoTpToCommand");
public string Name => "echoteleportperson";
public string ShortName => "etp";
public string Description => "Teleport to a player by name or Steam ID suffix. Usage: /echotpto <name|steamid_suffix|persona> [x y z]";
public string Namespace => "echo";
public void Execute(string[] args)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_0159: Unknown result type (might be due to invalid IL or missing references)
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /echotpto <name|steamid_suffix|persona> [x y z]");
return;
}
Vector3 zero = Vector3.zero;
string text;
if (args.Length >= 4 && float.TryParse(args[^3], out var result) && float.TryParse(args[^2], out var result2) && float.TryParse(args[^1], out var result3))
{
((Vector3)(ref zero))..ctor(result, result2, result3);
text = string.Join(" ", args, 0, args.Length - 3);
}
else
{
text = string.Join(" ", args);
}
text = text.Trim();
PlayerDetail val = PlayerUtils.FindPlayerByQuery(text);
if (val == null)
{
ChatUtils.AddGlobalNotification("Player \"" + text + "\" not found.");
return;
}
Vector3 val2 = val.Position + zero;
string text2 = ChatUtils.CleanTMPTags(val.UserName).Trim();
Logger.LogInfo((object)$"Teleporting to {text2} at {val.Position} + offset {zero} = {val2}");
MoveUtil.Teleport(val2);
string text3 = ((zero == Vector3.zero) ? "" : $" (+{zero.x}, +{zero.y}, +{zero.z})");
ChatUtils.AddGlobalNotification("Teleporting to " + text2 + text3 + ".");
}
}
public class EchoToggleCommand : IChatCommand, IComparable<IChatCommand>
{
public const string CMD = "echotoggle";
public string Name => "echotoggle";
public string ShortName => "et";
public string Description => "Toggle Echo feature on/off. ";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (EchoPlugin.EnableFeature != null)
{
EchoPlugin.EnableFeature.Value = !EchoPlugin.EnableFeature.Value;
ChatUtils.AddGlobalNotification("Echo feature is now " + (EchoPlugin.EnableFeature.Value ? "enabled" : "disabled") + ".");
}
}
}
public class EchoUnfollowCommand : IChatCommand, IComparable<IChatCommand>
{
public string Name => "echounfollow";
public string ShortName => "eu";
public string Description => "Stop following the current target.";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (!PlayerMovementControllerPatch.IsFollowing)
{
ChatUtils.AddGlobalNotification("Not currently following anyone.");
return;
}
PlayerMovementControllerPatch.StopFollowing();
ChatUtils.AddGlobalNotification("Stopped following.");
}
}
public class EchoUnsyncRotationCommand : IChatCommand, IComparable<IChatCommand>
{
public string Name => "echounsyncrotation";
public string ShortName => "eur";
public string Description => "Stop syncing rotation to the current target.";
public string Namespace => "echo";
public void Execute(string[] args)
{
if (!PlayerMovementControllerPatch.IsSyncingRotation)
{
ChatUtils.AddGlobalNotification("Not currently syncing rotation.");
return;
}
PlayerMovementControllerPatch.StopSyncingRotation();
ChatUtils.AddGlobalNotification("Stopped syncing rotation.");
}
}
}