using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
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.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: AssemblyCompany("ValheimCrossServerPortals")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Cross Server Portals Valheim Mod")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ValheimCrossServerPortals")]
[assembly: AssemblyTitle("ValheimCrossServerPortals")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class IsReadOnlyAttribute : Attribute
{
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace Lunarbin.Valheim.CrossServerPortals
{
[BepInPlugin("lunarbin.games.valheim", "Valheim Cross Server Portals", "0.2.1")]
public class CrossServerPortals : BaseUnityPlugin
{
public struct ServerInfo
{
public string Address;
public ushort Port;
public string SourceTag;
public string TargetTag;
public ServerInfo()
{
Address = null;
Port = 0;
SourceTag = null;
TargetTag = null;
}
public ServerInfo(string sourceTag, string address, ushort port = 0, string targetTag = "")
{
Address = address;
Port = port;
SourceTag = sourceTag;
TargetTag = targetTag;
}
public ServerInfo(string sourceTag, string address, string targetTag = "")
{
Address = address;
Port = 0;
TargetTag = targetTag;
SourceTag = sourceTag;
}
}
private readonly struct SEData
{
public int Name { get; }
public float Ttl { get; }
public float Time { get; }
public SEData(int name, float ttl, float time)
{
Name = name;
Ttl = ttl;
Time = time;
}
}
[HarmonyPatch(typeof(Player), "Load")]
private static class PatchPlayerLoad
{
private static void Postfix(Player __instance)
{
if (!preserveStatusEffects.Value || StatusEffects.Count <= 0)
{
return;
}
foreach (SEData statusEffect2 in StatusEffects)
{
((Character)__instance).GetSEMan().AddStatusEffect(statusEffect2.Name, false, 0, 0f);
StatusEffect statusEffect = ((Character)__instance).GetSEMan().GetStatusEffect(statusEffect2.Name);
if ((Object)(object)statusEffect != (Object)null)
{
statusEffect.m_ttl = statusEffect2.Time;
}
}
StatusEffects.Clear();
}
}
[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
internal static class PatchTeleport
{
private static bool Prefix(TeleportWorld __instance, ref Player player)
{
string text = __instance.GetText();
if (PortalTagIsToServer(text))
{
((Character)player).Message((MessageType)2, "Teleporting to " + text, 0, (Sprite)null);
TeleportToServer(text, __instance);
return false;
}
return true;
}
}
[HarmonyPatch(typeof(TeleportWorld), "HaveTarget")]
internal class PatchTeleportWorldHaveTarget
{
private static Color defaultColor = Color.white;
private static bool Prefix(ref bool __result, TeleportWorld __instance)
{
//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_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//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_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
if (defaultColor == Color.white && __instance.m_colorTargetfound != Color.green)
{
defaultColor = __instance.m_colorTargetfound;
}
string text = __instance.GetText();
if (!PortalTagIsToServer(text))
{
__instance.m_colorTargetfound = defaultColor;
return true;
}
__instance.m_colorTargetfound = Color.green;
__result = true;
return false;
}
}
[HarmonyPatch(typeof(TeleportWorld), "TargetFound")]
internal class PatchTeleportWorldTargetFound
{
private static Color defaultColor = Color.white;
private static bool Prefix(ref bool __result, TeleportWorld __instance)
{
//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_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//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_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
if (defaultColor == Color.white && __instance.m_colorTargetfound != Color.green)
{
defaultColor = __instance.m_colorTargetfound;
}
string text = __instance.GetText();
if (!PortalTagIsToServer(text))
{
__instance.m_colorTargetfound = defaultColor;
return true;
}
__instance.m_colorTargetfound = Color.green;
__result = true;
return false;
}
}
[HarmonyPatch(typeof(TeleportWorld), "Interact")]
internal class PatchTeleportWorldInteract
{
private static bool Prefix(ref Humanoid human, ref bool hold, ref bool __result, TeleportWorld __instance)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
if (hold)
{
__result = false;
return false;
}
if (!PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, true, false))
{
((Character)human).Message((MessageType)2, "$piece_noaccess", 0, (Sprite)null);
__result = true;
return false;
}
TextInput.instance.RequestText((TextReceiver)(object)__instance, "$piece_portal_tag", 50);
__result = true;
return false;
}
}
[HarmonyPatch(typeof(FejdStartup), "Awake")]
internal class PatchFejdStartupStart
{
private static void Postfix()
{
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Expected O, but got Unknown
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Expected O, but got Unknown
if (ServerToJoin.HasValue && TeleportingToServer && !HasJoinedServer)
{
ServerStatus serverToJoin = new ServerStatus((ServerJoinData)new ServerJoinDataDedicated($"{ServerToJoin?.Address}:{ServerToJoin?.Port}"));
FejdStartup.instance.SetServerToJoin(serverToJoin);
FejdStartup.instance.JoinServer();
}
}
}
[HarmonyPatch(typeof(FejdStartup), "ShowCharacterSelection")]
internal class PatchFejdStartupShowCharacterSelection
{
private static void Postfix()
{
if (ServerToJoin.HasValue && TeleportingToServer && !HasJoinedServer)
{
HasJoinedServer = true;
FejdStartup.instance.OnCharacterStart();
}
}
}
[HarmonyPatch(typeof(Game), "SpawnPlayer")]
internal class PatchGameSpawnPlayer
{
private static void Prefix(ref Vector3 spawnPoint)
{
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: 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_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: 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_012b: 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_0137: 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_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
if (TeleportingToServer && ServerToJoin.HasValue && ServerToJoin?.TargetTag != "")
{
List<ZDO> list = new List<ZDO>();
int num = 0;
ZDOMan.instance.GetAllZDOsWithPrefabIterative(portalPrefab, list, ref num);
foreach (ZDO item in list)
{
if (item != null)
{
string @string = item.GetString(ZDOVars.s_tag, "");
if (@string == ServerToJoin?.TargetTag || PortalTagToServerInfo(@string)?.SourceTag == ServerToJoin?.TargetTag)
{
Vector3 position = item.GetPosition();
Quaternion rotation = item.GetRotation();
Vector3 val = rotation * Vector3.forward;
spawnPoint = position + val * PortalExitDistance + Vector3.up;
break;
}
}
}
}
TeleportingToServer = false;
ServerToJoin = null;
}
}
[HarmonyPatch(typeof(Game), "Start")]
internal class PatchGameStart
{
private static void Postfix()
{
knownPortals.Clear();
((MonoBehaviour)Game.instance).StartCoroutine(FetchPortals());
}
private static IEnumerator FetchPortals()
{
while (true)
{
List<ZDO> portals = new List<ZDO>();
int index = 0;
while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(portalPrefab, portals, ref index))
{
yield return null;
}
if (ZNet.instance.IsServer())
{
foreach (ZDO zdo in portals.Except(knownPortals))
{
ZDOMan.instance.ForceSendZDO(zdo.m_uid);
}
}
knownPortals = portals;
yield return (object)new WaitForSeconds(10f);
}
}
}
[HarmonyPatch(typeof(ZDOMan), "AddPeer")]
internal class PatchZDOManAddPeer
{
private static void Postfix(ZDOMan __instance, ZNetPeer netPeer)
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
if (!ZNet.instance.IsServer())
{
return;
}
foreach (ZDO knownPortal in knownPortals)
{
__instance.ForceSendZDO(netPeer.m_uid, knownPortal.m_uid);
}
}
}
private static string PortalTagRegex = "^(?<SourceTag>[A-z0-9]+)\\|(?<Server>[A-z0-9\\.]+):?(?<Port>[0-9]+)?\\|?(?<TargetTag>[A-z0-9]+)?$";
public static ServerInfo? ServerToJoin = null;
public static bool TeleportingToServer = false;
public static bool HasJoinedServer = false;
public static float PortalExitDistance = 0f;
public static ConfigEntry<bool> preserveStatusEffects;
private static List<SEData> StatusEffects = new List<SEData>();
public static string portalPrefab = "portal_wood";
public static List<ZDO> knownPortals = new List<ZDO>();
public static readonly ManualLogSource Logger = Logger.CreateLogSource("CrossServerPortals");
private readonly Harmony harmony = new Harmony("lunarbin.games.valheim");
private void Awake()
{
harmony.PatchAll();
preserveStatusEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PreserveStatusEffects", true, "Preserve Status Effects while switching servers (such as rested, wet, etc.)");
}
public static void TeleportToServer(string tag, TeleportWorld instance)
{
ServerToJoin = PortalTagToServerInfo(tag);
if (ServerToJoin.HasValue)
{
if (preserveStatusEffects.Value)
{
foreach (StatusEffect statusEffect in ((Character)Player.m_localPlayer).GetSEMan().GetStatusEffects())
{
StatusEffects.Add(new SEData(statusEffect.NameHash(), statusEffect.m_ttl, (statusEffect.m_ttl > 0f) ? statusEffect.GetRemaningTime() : 0f));
}
}
MovePlayerToPortalExit(ref Player.m_localPlayer, ref instance);
Game.instance.IncrementPlayerStat((PlayerStatType)15, 1f);
TeleportingToServer = true;
HasJoinedServer = false;
Game.instance.Logout(true, true);
}
else
{
((Character)Player.m_localPlayer).Message((MessageType)2, "Invalid portal tag: " + tag, 0, (Sprite)null);
}
}
public static void MovePlayerToPortalExit(ref Player player, ref TeleportWorld portal)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: 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_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: 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)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
Vector3 position = ((Component)portal).transform.position;
Quaternion rotation = ((Component)portal).transform.rotation;
Vector3 val = rotation * Vector3.forward;
Vector3 position2 = position + val * portal.m_exitDistance + Vector3.up;
((Component)player).transform.position = position2;
((Component)player).transform.rotation = rotation;
PortalExitDistance = portal.m_exitDistance * 2f;
}
public static bool PortalTagIsToServer(string tag)
{
return Regex.IsMatch(tag, PortalTagRegex);
}
public static ServerInfo? PortalTagToServerInfo(string tag)
{
Match match = Regex.Match(tag, PortalTagRegex);
if (match.Success)
{
return new ServerInfo(match.Groups["SourceTag"].Value, match.Groups["Server"].Value, ushort.Parse(match.Groups["Port"].Value ?? "0"), match.Groups["TargetTag"].Value);
}
return null;
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "ValheimCrossServerPortals";
public const string PLUGIN_NAME = "ValheimCrossServerPortals";
public const string PLUGIN_VERSION = "1.0.0";
}
}