Decompiled source of CaptainHook v2.5.3

CaptainHook.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("CaptainHook")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CaptainHook")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e944f7cd-03c8-4672-bfbe-e19ac9566a48")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace CaptainHookMod;

[BepInPlugin("Caenos.CaptainHook", "CaptainHook", "2.5.3")]
public class CaptainHook : BaseUnityPlugin
{
	internal static ManualLogSource Logger;

	private HttpListener httpListener;

	private Thread httpThread;

	private ConfigEntry<int> configPort;

	private ConfigEntry<string> configIP;

	private ConfigEntry<string> configBotName;

	private static DateTime serverStartTime;

	private void Awake()
	{
		Logger = ((BaseUnityPlugin)this).Logger;
		configPort = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ServerPort", 25662, "Port used for the HTTP server.");
		configIP = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ServerIP", "127.0.0.1", "Public IP the Discord bot should connect to.");
		configBotName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "BotDisplayName", "CaptainHook", "Display name used by the bot.");
		Logger.LogInfo((object)$"[{configBotName.Value}] Config loaded. Listening on {configIP.Value}:{configPort.Value}");
		serverStartTime = DateTime.UtcNow;
		StartHttpServer();
	}

	private void StartHttpServer()
	{
		try
		{
			httpListener = new HttpListener();
			httpListener.Prefixes.Add($"http://*:{configPort.Value}/");
			httpListener.Start();
			Logger.LogInfo((object)$"[{configBotName.Value}] HTTP server listening on port {configPort.Value}.");
			httpThread = new Thread(HttpServerLoop);
			httpThread.IsBackground = true;
			httpThread.Start();
		}
		catch (Exception arg)
		{
			Logger.LogError((object)$"[{configBotName.Value}] Failed to start HTTP server: {arg}");
		}
	}

	private void HttpServerLoop()
	{
		while (httpListener != null && httpListener.IsListening)
		{
			try
			{
				HttpListenerContext context = httpListener.GetContext();
				HttpListenerRequest request = context.Request;
				HttpListenerResponse response = context.Response;
				string text = request.Url.AbsolutePath.Trim(new char[1] { '/' }).ToLower();
				string text2 = "";
				switch (text)
				{
				case "stats":
					text2 = GeneratePlayerStats();
					break;
				case "ping":
					text2 = "\ud83c\udfd3 Pong!";
					break;
				case "version":
					text2 = "\ud83d\udee0\ufe0f " + configBotName.Value + " v2.5.3 — Made by Caenos";
					break;
				case "uptime":
					text2 = $"⏱\ufe0f Uptime: {DateTime.UtcNow - serverStartTime:hh\\:mm\\:ss}";
					break;
				case "whereis":
					text2 = FindPlayerZone(request.QueryString["name"]);
					break;
				case "day":
					text2 = GetWorldTime();
					break;
				default:
					response.StatusCode = 404;
					text2 = "404 Not Found";
					break;
				}
				byte[] bytes = Encoding.UTF8.GetBytes(text2);
				response.ContentEncoding = Encoding.UTF8;
				response.ContentType = "text/plain; charset=utf-8";
				response.ContentLength64 = bytes.Length;
				response.OutputStream.Write(bytes, 0, bytes.Length);
				response.OutputStream.Close();
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"[{configBotName.Value}] HTTP server error: {arg}");
			}
		}
	}

	private string GeneratePlayerStats()
	{
		try
		{
			ZNet instance = ZNet.instance;
			List<ZNetPeer> list = ((instance != null) ? instance.GetConnectedPeers() : null);
			if (list == null || list.Count == 0)
			{
				return "\ud83d\udc7b No players online in the spooky Underworld.";
			}
			List<string> list2 = (from p in list
				select p.m_playerName into name
				where !string.IsNullOrEmpty(name)
				select name).Distinct().ToList();
			return string.Format("{0} Player(s) online in the spooky Underworld: {1}", list2.Count, string.Join(", ", list2));
		}
		catch (Exception arg)
		{
			Logger.LogError((object)$"Failed to get player stats: {arg}");
			return "⚠\ufe0f Error getting player info.";
		}
	}

	private string FindPlayerZone(string name)
	{
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//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_0086: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrEmpty(name))
		{
			return "⚠\ufe0f You must provide a player name.";
		}
		List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers();
		foreach (ZNetPeer item in connectedPeers)
		{
			if (item.m_playerName.Equals(name, StringComparison.OrdinalIgnoreCase))
			{
				ZDO zDO = ZDOMan.instance.GetZDO(item.m_characterID);
				if (zDO != null)
				{
					Vector3 position = zDO.GetPosition();
					Biome biome = WorldGenerator.instance.GetBiome(position);
					return $"\ud83d\udee1\ufe0f {name} is currently in the {biome}.";
				}
				return "\ud83d\udee1\ufe0f " + name + " is online but their position is unknown.";
			}
		}
		return "❓ Player '" + name + "' not found.";
	}

	private string GetWorldTime()
	{
		try
		{
			int day = EnvMan.instance.GetDay();
			float dayFraction = EnvMan.instance.GetDayFraction();
			float num = (float)(day - 1) * 2400f + dayFraction * 2400f;
			int num2 = (int)(num % 2400f / 100f);
			int num3 = (int)(num % 100f * 0.6f);
			return $"\ud83d\udcc5 Day {day}, {num2:D2}:{num3:D2} in Valheim.";
		}
		catch (Exception arg)
		{
			Logger.LogError((object)$"Failed to get world time: {arg}");
			return "⚠\ufe0f Could not read in-game time.";
		}
	}

	private void OnDestroy()
	{
		if (httpListener != null)
		{
			httpListener.Stop();
			httpListener.Close();
			httpListener = null;
		}
		httpThread?.Abort();
	}
}