private static bool Prefix(ref ZNet __instance, ZRpc rpc, ZPackage pkg) { if (__instance.IsServer()) { string self = ""; if (pkg.Size() > 32) { pkg.SetPos(pkg.Size() - 32 - 1); if (pkg.ReadByte() == (byte)32) { pkg.SetPos(pkg.GetPos() - 1); self = pkg.ReadString(); } } ZLog.Log((object)("[AntiMods]: Got client hash: " + self + "\nmine: " + VACPlugin.PluginsHash)); ZLog.LogWarning("Plugins Hash is Equals: " + !self.Equals(VACPlugin.PluginsHash) + " ForceMods: " + VACPlugin.forcesamemods.Value); ZLog.LogWarning("Is in Admin List: " + !ZNet.instance.m_adminList.Contains(rpc.GetSocket().GetHostName()) + "Admin Bypass: "******"[AntiMods]: Kicking Client: " + rpc.GetSocket().GetEndPointString() + " (incompatible mods)")); rpc.Invoke("Error", (object)num); return(false); } ZLog.Log((object)("[AntiMods]: Accepting Client: " + rpc.GetSocket().GetEndPointString())); } return(true); }
// Hook RPC_PeerInfo to check in front of the original method private static void ZNet_RPC_PeerInfo(On.ZNet.orig_RPC_PeerInfo orig, ZNet self, ZRpc rpc, ZPackage pkg) { if (ZNet.instance.IsServerInstance() || ZNet.instance.IsLocalInstance()) { try { var clientVersion = new ModuleVersionData(clientVersions[rpc.GetSocket().GetEndPointString()]); var serverVersion = new ModuleVersionData(GetEnforcableMods().ToList()); // Remove from list clientVersions.Remove(rpc.GetSocket().GetEndPointString()); // Compare and disconnect when not equal if (!clientVersion.Equals(serverVersion)) { rpc.Invoke("Error", 3); return; } } catch (EndOfStreamException) { Logger.LogError("Reading beyond end of stream. Probably client without Jotunn tried to connect."); // Client did not send appended package, just disconnect with the incompatible version error rpc.Invoke("Error", 3); return; } catch (KeyNotFoundException ex) { // Vanilla client trying to connect? // Check mods, if there are some installed on the server which need also to be on the client if (GetEnforcableMods().Any(x => x.Item3 == CompatibilityLevel.EveryoneMustHaveMod)) { // There is a mod, which needs to be client side too // Lets disconnect the vanilla client with Incompatible Version message rpc.Invoke("Error", 3); return; } } } else { // If we got this far on client side, clear lastServerVersion again lastServerVersion = null; } // call original method orig(self, rpc, pkg); }
public static void CharacterUpdate(ZRpc rpc, ZPackage data) { // Are we the server? Update the character. if (ZNet.instance.IsServer()) { Debug.Log("Client->Server CharacterUpdate"); string hostName = rpc.GetSocket().GetHostName(); ZNetPeer peer = ZNet.instance.GetPeerByHostName(hostName); string PlayerNameRaw = peer.m_playerName; string PlayerName = ""; if (WorldofValheimServerSideCharacters.AllowMultipleCharacters.Value) { PlayerName = Regex.Replace(PlayerNameRaw, @"<[^>]*>", String.Empty); } else { PlayerName = "Single_Character_Mode"; } string CharacterLocation = Util.GetCharacterPath(hostName, PlayerName); Debug.Log($"Saving character from SteamID {hostName}."); Util.WriteCharacter(CharacterLocation, Util.Decompress(data).GetArray()); return; } // Are we the client? Send our character. Debug.Log("Server->Client CharacterUpdate"); if (Player.m_localPlayer != null) { rpc.Invoke("CharacterUpdate", new object[] { Util.Compress(Game.instance.GetPlayerProfile().Serialize(Player.m_localPlayer, true)) }); return; } }
public static IEnumerator Client2(ZRpc rpc) { rpc.Invoke("Client", new object[] { Client.Serialize(rpc.GetSocket().GetHostName()) }); yield return(new WaitForSeconds(1)); }
public static IEnumerator ZoneHandler2(ZRpc rpc) { rpc.Invoke("ZoneHandler", new object[] { ZoneHandler.Serialize(rpc.GetSocket().GetHostName()) }); yield return(new WaitForSeconds(1)); }
/// <summary> /// Hook ZNet.RPC_PeerInfo on the server to send initial data /// </summary> /// <param name="self"></param> /// <param name="rpc"></param> /// <param name="__state"></param> private void ZNet_RPC_Pre_PeerInfo(ZNet self, ZRpc rpc, ref PeerInfoBlockingSocket __state) { PeerInfoBlockingSocket bufferingSocket = null; // Create buffering socket if (self.IsServer()) { bufferingSocket = new PeerInfoBlockingSocket(rpc.GetSocket()); rpc.m_socket = bufferingSocket; } __state = bufferingSocket; }
public static void RPC_UpdateInventory(ZRpc rpc, ZPackage pkg) { String characterName = pkg.ReadString(); int itemsCount = pkg.ReadInt(); String steamId = rpc.GetSocket().GetEndPointString(); List <Server_ItemData> playerItems = new List <Server_ItemData>(); for (int i = 0; i < itemsCount; i++) { Server_ItemData data = new Server_ItemData { Name = pkg.ReadString(), Stack = pkg.ReadInt(), Quality = pkg.ReadInt(), Variant = pkg.ReadInt() }; playerItems.Add(data); } String dbId = $"{steamId}_{characterName}"; var dbPlayer = Instance.DB.GetPlayerById(dbId); if (dbPlayer == null) { dbPlayer = new DBClasses.DBPlayer() { DBPlayerId = dbId, SteamId = steamId, CharacterName = characterName, Items = new List <DBClasses.DBItem>() }; foreach (var item in playerItems) { dbPlayer.Items.Add(new DBClasses.DBItem() { ItemName = item.Name, PlayerId = dbPlayer.DBPlayerId, StackCount = item.Stack, Quality = item.Quality, Variant = item.Variant }); } Instance.DB.InsertPlayer(dbPlayer); } else { Instance.DB.UpdatePlayer(dbPlayer); } }
private static void ZNet__SendPeerInfo(ZNet __instance, ZRpc rpc) { // Are we the client? Then get out! if (!__instance.IsServer()) { return; } // Ok now that that's done. Lets gogogo Servers! Debug.Log("Server->Client CharacterData"); rpc.Invoke("CharacterData", new object[] { Util.Compress(Util.LoadOrMakeCharacter(rpc.GetSocket().GetHostName())) }); ServerState.Connections.Add(new ServerState.ConnectionData { rpc = rpc }); }
public static void ExitServer(ZRpc rpc, ZPackage data) { if (ZNet.instance.IsServer()) { Debug.Log("Client->Server ExitServer"); RPC.CharacterUpdate(rpc, data); rpc.Invoke("ExitServer", new object[] { new ZPackage() }); Debug.Log($"Removing Client {rpc.GetSocket().GetHostName()} from our list"); ServerState.Connections.RemoveAll((ServerState.ConnectionData conn) => conn.rpc.GetSocket() == rpc.GetSocket()); Debug.Log("Connections " + ServerState.Connections.Count.ToString()); return; } Debug.Log("Server->Client ExitServer"); ServerState.Connections.RemoveAll((ServerState.ConnectionData conn) => conn.rpc.GetSocket() == rpc.GetSocket()); ServerState.ClientCanDC = true; }
/// <summary> /// Store server's message. /// </summary> /// <param name="sender"></param> /// <param name="data"></param> private static void RPC_Jotunn_ReceiveVersionData(ZRpc sender, ZPackage data) { Logger.LogDebug($"Received Version package from {sender.m_socket.GetEndPointString()}"); if (!ZNet.instance.IsClientInstance()) { clientVersions[sender.m_socket.GetEndPointString()] = data; var clientVersion = new ModuleVersionData(clientVersions[sender.GetSocket().GetEndPointString()]); var serverVersion = new ModuleVersionData(GetEnforcableMods().ToList()); if (!clientVersion.Equals(serverVersion)) { // Disconnect if mods are not network compatible sender.Invoke("Error", 3); } } else { lastServerVersion = data; } }
private static bool ZNet_RPC_PeerInfo(ZNet __instance, ZRpc rpc, ZPackage pkg) { if (!ZNet.instance.IsClientInstance()) { // Vanilla client trying to connect? if (!ClientVersions.ContainsKey(rpc.GetSocket().GetEndPointString())) { // Check mods, if there are some installed on the server which need also to be on the client if (GetEnforcableMods().Any(x => x.Item3 == CompatibilityLevel.EveryoneMustHaveMod || x.Item3 == CompatibilityLevel.ClientMustHaveMod)) { // There is a mod, which needs to be client side too // Lets disconnect the vanilla client with Incompatible Version message Logger.LogWarning("Disconnecting vanilla client with incompatible version message. " + "There are mods that need to be installed on the client"); rpc.Invoke("Error", (int)ZNet.ConnectionStatus.ErrorVersion); return(false); } } else { var serverData = new ModuleVersionData(GetEnforcableMods().ToList()); var clientData = new ModuleVersionData(ClientVersions[rpc.m_socket.GetEndPointString()]); if (!CompareVersionData(serverData, clientData)) { // Disconnect if mods are not network compatible Logger.LogWarning("RPC_PeerInfo: Disconnecting modded client with incompatible version message. " + "Mods are not compatible"); rpc.Invoke("Error", (int)ZNet.ConnectionStatus.ErrorVersion); return(false); } } } return(true); }
private static IEnumerator SendSettings(ZNet instance, ZRpc rpc, ZPackage pkg) { byte[] ArraySlice(byte[] source, int offset, int length) { var target = new byte[length]; Buffer.BlockCopy(source, offset, target, 0, length); return(target); } var peer = instance.GetPeers().First(p => p.m_rpc == rpc); if (!Settings.EnabledForThisWorld) { Log($"Skipping sending settings to {PeerName(peer)}, as Better Continents is not enabled in this world"); } else { Log($"World is using Better Continents, so client version must match server version {ModInfo.Name}"); if (!ClientInfo.TryGetValue(peer.m_uid, out var bcClientInfo)) { Log($"Client info for {PeerName(peer)} not found, client has an old version of Better Continents, or none!"); rpc.Invoke("Error", ZNet.ConnectionStatus.ErrorConnectFailed); ZNet.instance.Disconnect(peer); yield break; } else if (bcClientInfo.version != ModInfo.Version) { Log($"Client {PeerName(peer)} version {bcClientInfo.version} doesn't match server version {ModInfo.Version}"); peer.m_rpc.Invoke("Error", 69); ZNet.instance.Disconnect(peer); yield break; } else { Log($"Client {PeerName(peer)} version {bcClientInfo.version} matches server version {ModInfo.Version}"); } // This was the initial way that versioning was implemented, before the client->server way, so may // as well leave it in Log($"Sending server version {ModInfo.Version} to client for bi-lateral version agreement"); rpc.Invoke("BetterContinentsVersion", ModInfo.Version); var settingsPackage = new ZPackage(); var cleanSettings = Settings.Clean(); cleanSettings.Serialize(settingsPackage); if (WorldCache.CacheItemExists(settingsPackage, bcClientInfo.worldCache)) { // We send hash and id string cacheId = WorldCache.PackageID(settingsPackage); Log($"Client {PeerName(peer)} already has cached settings for world, instructing it to load those (id {cacheId})"); rpc.Invoke("BetterContinentsConfigLoadFromCache", cacheId); } else { Log($"Client {PeerName(peer)} doesn't have cached settings, sending them now"); cleanSettings.Dump(); var settingsData = settingsPackage.GetArray(); Log($"Sending settings package header for {settingsData.Length} byte stream"); rpc.Invoke("BetterContinentsConfigStart", settingsData.Length, GetHashCode(settingsData)); const int SendChunkSize = 256 * 1024; for (int sentBytes = 0; sentBytes < settingsData.Length;) { int packetSize = Mathf.Min(settingsData.Length - sentBytes, SendChunkSize); var packet = ArraySlice(settingsData, sentBytes, packetSize); rpc.Invoke("BetterContinentsConfigPacket", sentBytes, GetHashCode(packet), new ZPackage(packet)); // Make sure to flush or we will saturate the queue... rpc.GetSocket().Flush(); sentBytes += packetSize; Log($"Sent {sentBytes} of {settingsData.Length} bytes"); float timeout = Time.time + 30; yield return(new WaitUntil(() => rpc.GetSocket().GetSendQueueSize() < SendChunkSize || Time.time > timeout)); if (Time.time > timeout) { Log($"Timed out sending config to client {PeerName(peer)} after 30 seconds, disconnecting them"); peer.m_rpc.Invoke("Error", ZNet.ConnectionStatus.ErrorConnectFailed); ZNet.instance.Disconnect(peer); yield break; } } } yield return(new WaitUntil(() => ClientInfo[peer.m_uid].readyForPeerInfo || !peer.m_socket.IsConnected())); } RPC_PeerInfo(instance, rpc, pkg); }
//CALLED ON SERVER, Should contain ZDOID and Inventory public static void RPC_CharacterIDX(ZRpc rpc, ZPackage pkg) { ZDOID characterID = pkg.ReadZDOID(); ZNetPeer peer = (ZNetPeer)_GetPeerMethod.Invoke(ZNet.instance, new object[] { rpc }); if (peer != null) { peer.m_characterID = characterID; if (Configs.ShowDebugMessages.Value) { ZLog.Log($"Got character ZDOID with inventory from {peer.m_playerName} : {characterID}!"); } } ZPackage inventoryPackage = pkg.ReadPackage(); String characterName = inventoryPackage.ReadString(); int itemsCount = inventoryPackage.ReadInt(); String steamId = rpc.GetSocket().GetEndPointString(); if (Configs.ShowDebugMessages.Value) { Instance.Logger.LogInfo($"Getting player {characterName}'s ({steamId}) inventory..."); } List <Server_ItemData> playerItems = new List <Server_ItemData>(); for (int i = 0; i < itemsCount; i++) { Server_ItemData data = new Server_ItemData { Name = inventoryPackage.ReadString(), Stack = inventoryPackage.ReadInt(), Quality = inventoryPackage.ReadInt(), Variant = inventoryPackage.ReadInt() }; playerItems.Add(data); } if (Configs.ShowDebugMessages.Value) { Instance.Logger.LogInfo($"Found {playerItems.Count} items in {characterName}'s inventory."); } String dbId = $"{steamId}_{characterName}"; var dbPlayer = Instance.DB.GetPlayerById(dbId); if (dbPlayer == null) { if (Configs.ShowDebugMessages.Value) { Instance.Logger.LogInfo($"{characterName} is a new character!"); } DBClasses.DBPlayer[] characters = Instance.DB.GetPlayersBySteamId(steamId); if (characters.Length >= Configs.MaxCharactersPerPlayer.Value) { rpc.Invoke("Error", new object[] { (int)ZNet.ConnectionStatus.ErrorVersion }); return; } dbPlayer = new DBClasses.DBPlayer() { DBPlayerId = dbId, SteamId = steamId, CharacterName = characterName, Items = new List <DBClasses.DBItem>() }; foreach (var item in playerItems) { dbPlayer.Items.Add(new DBClasses.DBItem() { ItemName = item.Name, PlayerId = dbPlayer.DBPlayerId, StackCount = item.Stack, Quality = item.Quality, Variant = item.Variant }); } Instance.DB.InsertPlayer(dbPlayer); } else { bool isSame = true; if (dbPlayer.Items.Count != playerItems.Count) { isSame = false; } else { for (int i = 0; i < dbPlayer.Items.Count; i++) { if (dbPlayer.Items[i].ItemName != playerItems[i].Name || dbPlayer.Items[i].StackCount != playerItems[i].Stack || dbPlayer.Items[i].Quality != playerItems[i].Quality || dbPlayer.Items[i].Variant != playerItems[i].Variant) { isSame = false; break; } } } if (isSame) { if (Configs.ShowDebugMessages.Value) { Instance.Logger.LogInfo($"{characterName} is still the same"); } dbPlayer.LastLoggedIn = DateTime.Now; Instance.DB.UpdatePlayer(dbPlayer); } else { if (Configs.ShowDebugMessages.Value) { Instance.Logger.LogWarning($"{characterName} is NOT the same!"); } rpc.Invoke("Error", new object[] { (int)ZNet.ConnectionStatus.ErrorVersion }); } } }
private static void RPC_ConsoleCommand(ZRpc rpc, string command) { if (!modEnabled.Value || !ZNet.instance.IsServer()) { return; } ZNetPeer peer = Traverse.Create(ZNet.instance).Method("GetPeer", new object[] { rpc }).GetValue <ZNetPeer>(); var steamID = (peer.m_socket as ZSteamSocket).GetPeerID(); Dbgl($"RPC_ConsoleCommand received command {command} from {steamID}"); if (!Traverse.Create(ZNet.instance).Field("m_adminList").GetValue <SyncedList>().Contains(rpc.GetSocket().GetHostName())) { Dbgl("User is not admin!"); return; } var parts = command.Split(' ').Skip(1).ToArray(); string result = ""; if (parts[0] == "help") { result = "Usage:\r\n" + "serverrewards list users\r\n" + "serverrewards list packages\r\n" + "serverrewards give <steamID> <currency>\r\n" + "serverrewards give all <currency>\r\n" + "serverrewards set <steamID> <currency>\r\n" + "serverrewards set all <currency>\r\n" + "serverrewards givepackage <steamID> <packageID>\r\n" + "serverrewards givepackage all <packageID>\r\n" + "serverrewards spawn <spawnName>"; } else if (parts[0] == "list" && parts.Length == 2) { if (parts[1] == "users") { List <string> userList = new List <string>(); List <string> users = GetAllPlayerIDs(); var peerList = ZNet.instance.GetConnectedPeers(); foreach (string user in users) { string online = "(offline)"; var tp = peerList.Find(p => (p.m_socket as ZSteamSocket).GetPeerID().ToString() == user); if (tp != null) { online = tp.m_playerName + " (online)"; } userList.Add(user + " " + online); } result = string.Join("\r\n", userList); } else if (parts[1] == "packages") { List <string> packageList = new List <string>(); var packages = GetAllPackages(); foreach (PackageInfo p in packages) { packageList.Add(p.id + " " + p.price); } result = string.Join("\r\n", packageList); } else { result = "Syntax error."; } } else if (parts[0] == "give" && parts.Length == 3) { try { string id = GetSteamID(parts[1]); if (id == null) { result = "User not found."; } else if (AdjustCurrency(id, int.Parse(parts[2]))) { result = "Balance adjusted."; } else { result = "Error adjusting player balance."; } } catch { result = "Syntax error."; } } else if (parts[0] == "set" && parts.Length == 3) { try { string id = GetSteamID(parts[1]); if (id == null) { result = "User not found."; } else if (SetCurrency(id, int.Parse(parts[2]))) { result = "Balance set."; } else { result = "Error setting player balance."; } } catch { result = "Syntax error."; } } else if (parts[0] == "givepackage" && parts.Length == 3) { if (parts[1] == "all") { IEnumerable <string> users = GetAllPlayerIDs(); int count = 0; foreach (string user in users) { string r = GivePackage(parts[1], parts[2]); if (r == null) { count++; } } result = $"Package sent to {count} users!"; } else { string id = GetSteamID(parts[1]); if (id == null) { result = "User not found."; } else { result = GivePackage(id, parts[2]); if (result == null) { result = "Package sent!"; } } } } else if (parts[0] == "spawn" && parts.Length == 2) { GameObject prefab = ZNetScene.instance.GetPrefab(parts[1]); if (!prefab) { result = $"Item {parts[1]} not found!"; } else { var go = Instantiate(prefab, Player.m_localPlayer.transform.position + Player.m_localPlayer.transform.forward * 2f + Vector3.up, Quaternion.identity); Player.m_localPlayer.Message(MessageHud.MessageType.TopLeft, string.Format(packageInfoString.Value, Localization.instance.Localize(go.GetComponent <ItemDrop>().m_itemData.m_shared.m_name)), 0, null); } } else { result = "Syntax error."; } JsonCommand sendCommand = new JsonCommand() { command = "SendConsoleString", data = result }; rpc.Invoke("SendServerRewardsJSON", new object[] { JsonUtility.ToJson(sendCommand) }); Dbgl(result); }