Beispiel #1
0
        // 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);
        }
Beispiel #2
0
        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);
        }
 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;
     }
 }
Beispiel #4
0
            // ReSharper disable once InconsistentNaming
            private static void Postfix(int x, int y, bool __result)
            {
                if (__result == false)
                {
                    return;
                }

                if (_blockExplore)
                {
                    return;
                }

                if (!Store.IsSharingMap())
                {
                    return;
                }
                if (_ZNet.IsServer(_ZNet._instance))
                {
                    OnClientExplore(null, x, y);
                }
                else
                {
                    var  znet   = Traverse.Create(typeof(ZNet)).Field("m_instance").GetValue() as ZNet;
                    ZRpc server = _ZNet.GetServerRPC(znet);
                    server.Invoke("OnClientExplore", (object)x, (object)y);
                }
            }
Beispiel #5
0
            static bool Prefix(Terminal __instance)
            {
                if (!modEnabled.Value)
                {
                    return(true);
                }
                string text = __instance.m_input.text;

                if (text.ToLower().Equals($"{typeof(BepInExPlugin).Namespace.ToLower()} reset"))
                {
                    context.Config.Reload();
                    context.Config.Save();
                    ApplyConfig();
                    Traverse.Create(__instance).Method("AddString", new object[] { text }).GetValue();
                    Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} config reloaded" }).GetValue();
                    return(false);
                }
                if (text.ToLower().StartsWith($"{typeof(BepInExPlugin).Namespace.ToLower()} "))
                {
                    ZRpc serverRPC = ZNet.instance.GetServerRPC();
                    if (serverRPC != null)
                    {
                        serverRPC.Invoke("ServerRewardsConsoleCommand", new object[] { text });
                    }
                    Traverse.Create(__instance).Method("AddString", new object[] { text }).GetValue();
                    return(false);
                }
                return(true);
            }
 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));
 }
Beispiel #8
0
        private void WindowBuilder(int id)
        {
            GUI.DragWindow(new Rect(0, 0, windowWidth.Value, 20));
            GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(windowWidth.Value) });
            GUILayout.Label(windowTitleText, titleStyle);
            GUILayout.Label(string.Format(myCurrencyString.Value, string.Format(currencyString.Value, myCurrency)), currencyStyle);

            float width     = windowWidth.Value - 70;
            float itemWidth = width / packagesPerRow.Value;

            scrollPosition = GUILayout.BeginScrollView(scrollPosition, new GUILayoutOption[] { GUILayout.Width(windowWidth.Value - 20) });
            GUILayout.Space(10);
            GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(width) });
            GUILayout.BeginHorizontal();
            for (int i = 0; i < storePackages.Count; i++)
            {
                if (i > 0 && i % packagesPerRow.Value == 0)
                {
                    GUILayout.EndHorizontal();
                    GUILayout.Space(10);
                    GUILayout.BeginHorizontal();
                }
                PackageInfo pi      = storePackages[i];
                string      texture = textureDict.ContainsKey(pi.type) ? pi.type : "Common";
                GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(itemWidth) });
                if (GUILayout.Button(textureDict[texture], new GUILayoutOption[] { GUILayout.Width(itemWidth), GUILayout.Height(itemWidth) }))
                {
                    if (myCurrency >= pi.price)
                    {
                        ZRpc serverRPC = ZNet.instance.GetServerRPC();
                        if (serverRPC != null)
                        {
                            Dbgl("Requesting store data");
                            JsonCommand command = new JsonCommand()
                            {
                                command   = "BuyPackage",
                                packageid = pi.id
                            };
                            string commandJson = JsonUtility.ToJson(command);
                            Dbgl(commandJson);
                            serverRPC.Invoke("SendServerRewardsJSON", new object[] { commandJson });
                        }
                    }
                }

                GUILayout.Label(string.Format(packageString.Value, pi.name, pi.price), labelStyle, new GUILayoutOption[] { GUILayout.Width(itemWidth) });
                GUILayout.EndVertical();
            }
            GUILayout.EndHorizontal();
            GUILayout.Space(10);
            GUILayout.EndVertical();
            GUILayout.EndScrollView();
            GUILayout.EndVertical();
        }
Beispiel #9
0
        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 void Postfix(ZRpc rpc, ZPackage pkg, ZNet __instance)
 {
     if (__instance.IsServer())
     {
         for (var i = 0; i < mapSize * mapSize; i++)
         {
             if (getExplored(i))
             {
                 var z = new ZPackage();
                 z.Write(i % mapSize);
                 z.Write(i / mapSize);
                 rpc.Invoke("OnReceiveMapData", (object)z);
             }
         }
     }
 }
Beispiel #11
0
 static void Game_SavePlayerProfile(Game __instance, bool setLogoutPoint)
 {
     if (ZNet.instance != null && Player.m_localPlayer)
     {
         ZRpc serverRpc = ZNet.instance.GetServerRPC();
         if (serverRpc != null)
         {
             if (Configs.ShowDebugMessages.Value)
             {
                 UnityEngine.Debug.Log("Saving inventory");
             }
             Inventory playerInventory  = Player.m_localPlayer.GetInventory();
             ZPackage  inventoryPackage = Helper.PackageInventory(Player.m_localPlayer.GetPlayerName(), playerInventory);
             serverRpc.Invoke("UpdateInventory", new object[] { inventoryPackage });
         }
     }
 }
Beispiel #12
0
 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
     });
 }
        private static void SendPinsToClient(ZRpc client)
        {
            if (!Store.IsSharingPin())
            {
                return;
            }

            var z = ExplorationDatabase.PackPins(ExplorationDatabase.GetPins());

            if (client == null)
            {
                OnReceiveInitialDataPin(null, z);
            }
            else
            {
                client.Invoke("OnReceiveInitialDataPin", (object)z);
            }
        }
Beispiel #14
0
 public static void ValgrindHandshake(ZRpc rpc, int can, string id)
 {
     if (ZNet.instance.IsServer())
     {
     }
     else
     {
         int myCan = 0;
         foreach (var x in Plugin.FindObjectsOfType <GameObject>())
         {
             if (x.name == id)
             {
                 myCan++;
             }
         }
         rpc.Invoke("ValgrindHandshake", new object[] { myCan, "ErrorCount" });
     }
 }
        private void Update()
        {
            if (!modEnabled.Value)
            {
                return;
            }
            if (testing.Value)
            {
                if (AedenthornUtils.CheckKeyDown(openUIKey.Value))
                {
                    storeOpen = !storeOpen;
                }
                return;
            }
            if (ZNet.instance && Player.m_localPlayer && !AedenthornUtils.IgnoreKeyPresses(true) && AedenthornUtils.CheckKeyDown(openUIKey.Value))
            {
                Dbgl("Pressed hotkey");
                if (storeOpen)
                {
                    Traverse.Create(GameCamera.instance).Field("m_mouseCapture").SetValue(true);
                    Cursor.lockState = CursorLockMode.Locked;
                    Cursor.visible   = false;

                    Dbgl("Closing store");
                    storeOpen = false;
                }
                else
                {
                    ZRpc serverRPC = ZNet.instance.GetServerRPC();
                    if (serverRPC != null)
                    {
                        Dbgl("Requesting store data");
                        JsonCommand command = new JsonCommand()
                        {
                            command = "RequestStoreInfo",
                            id      = SteamUser.GetSteamID().ToString()
                        };
                        string commandJson = JsonUtility.ToJson(command);
                        Dbgl(commandJson);
                        serverRPC.Invoke("SendServerRewardsJSON", new object[] { commandJson });
                    }
                }
            }
        }
 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;
 }
Beispiel #17
0
        private static bool ZNet_SendPeerInfo(ZNet __instance, ZRpc rpc, string password)
        {
            if (ZNet.instance.IsClientInstance())
            {
                // If there was no server version response, Jötunn is not installed. Cancel if we have mandatory mods
                if (LastServerVersion == null &&
                    GetEnforcableMods().Any(x => x.Item3 == CompatibilityLevel.EveryoneMustHaveMod || x.Item3 == CompatibilityLevel.ServerMustHaveMod))
                {
                    Logger.LogWarning("Jötunn is not installed on the server. Client has mandatory mods. Cancelling connection");
                    rpc.Invoke("Disconnect");
                    LastServerVersion =
                        new ModuleVersionData(new List <Tuple <string, System.Version, CompatibilityLevel, VersionStrictness> >()).ToZPackage();
                    ZNet.m_connectionStatus = ZNet.ConnectionStatus.ErrorVersion;
                    return(false);
                }
            }

            return(true);
        }
        private static void SendChunkToClient(ZRpc client, int chunk)
        {
            if (chunk >= CHUNKS)
            {
                return;
            }

            var size       = ExplorationDatabase.MapSizeSquared / CHUNKS;
            var startIndex = chunk * (ExplorationDatabase.MapSizeSquared / CHUNKS);
            var z          = ExplorationDatabase.PackBoolArray(ExplorationDatabase.GetExplorationArray(), chunk, startIndex, size);

            if (client == null)
            {
                OnReceiveMapDataInitial(null, z);
            }
            else
            {
                client.Invoke("OnReceiveMapDataInitial", (object)z);
            }
        }
Beispiel #19
0
        private static void RPC_RquestConfigsSellThat(ZRpc rpc)
        {
            try
            {
                if (!ZNet.instance.IsServer())
                {
                    Log.LogWarning("Non-server instance received request for configs. Ignoring request.");
                }

                Log.LogInfo("Received request for configs.");

                ZPackage configPackage = new ZPackage();

                var package = new ConfigurationPackage(
                    ConfigurationManager.GeneralConfig,
                    ConfigurationManager.TraderBuyConfig,
                    ConfigurationManager.TraderSellConfig);

                Log.LogTrace("Serializing configs.");

                using (MemoryStream memStream = new MemoryStream())
                {
                    BinaryFormatter binaryFormatter = new BinaryFormatter();
                    binaryFormatter.Serialize(memStream, package);

                    byte[] serialized = memStream.ToArray();

                    configPackage.Write(serialized);
                }

                Log.LogTrace("Sending config package.");

                rpc.Invoke(nameof(RPC_ReceiveConfigsSellThat), new object[] { configPackage });

                Log.LogTrace("Finished sending config package.");
            }
            catch (Exception e)
            {
                Log.LogError("Unexpected error while attempting to create and send config package from server to client.", e);
            }
        }
Beispiel #20
0
        /// <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;
            }
        }
Beispiel #21
0
        /// <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 serverData = new ModuleVersionData(GetEnforcableMods().ToList());
                var clientData = new ModuleVersionData(data);

                if (!CompareVersionData(serverData, clientData))
                {
                    // Disconnect if mods are not network compatible
                    Logger.LogWarning("RPC_Jotunn_ReceiveVersionData: Disconnecting modded client with incompatible version message. " +
                                      "Mods are not compatible");
                    sender.Invoke("Error", (int)ZNet.ConnectionStatus.ErrorVersion);
                }
            }
            else
            {
                LastServerVersion = data;
            }
        }
Beispiel #22
0
 private void Update()
 {
     /*
      * if (AedenthornUtils.CheckKeyDown(openUIKey.Value))
      * {
      *  storeOpen = !storeOpen;
      *
      * }
      * return;
      */
     if (ZNet.instance && Player.m_localPlayer && !AedenthornUtils.IgnoreKeyPresses(true) && AedenthornUtils.CheckKeyDown(openUIKey.Value))
     {
         Dbgl("Pressed hotkey");
         if (storeOpen)
         {
             Dbgl("Closing store");
             storeOpen = false;
         }
         else
         {
             ZRpc serverRPC = ZNet.instance.GetServerRPC();
             if (serverRPC != null)
             {
                 Dbgl("Requesting store data");
                 JsonCommand command = new JsonCommand()
                 {
                     command = "RequestStoreInfo",
                     id      = SteamUser.GetSteamID().ToString()
                 };
                 string commandJson = JsonUtility.ToJson(command);
                 Dbgl(commandJson);
                 serverRPC.Invoke("SendServerRewardsJSON", new object[] { commandJson });
             }
         }
     }
 }
Beispiel #23
0
            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);
            }
Beispiel #24
0
 private static void ZNet_RPC_ServerHandshake(ZNet __instance, ZRpc rpc)
 {
     rpc.Invoke(nameof(RPC_Jotunn_ReceiveVersionData), new ModuleVersionData(GetEnforcableMods().ToList()).ToZPackage());
 }
Beispiel #25
0
        private static void RPC_SendJSON(ZRpc rpc, string json)
        {
            JsonCommand command = JsonUtility.FromJson <JsonCommand>(json);

            Dbgl($"RPC_SendJSON received command {command.command} {json} from id {command.id}");

            ZNetPeer peer    = Traverse.Create(ZNet.instance).Method("GetPeer", new object[] { rpc }).GetValue <ZNetPeer>();
            var      steamID = (peer.m_socket as ZSteamSocket).GetPeerID();

            if (ZNet.instance.IsServer())
            {
                context.UpdatePlayers(true);

                if (command.command == "BuyPackage")
                {
                    var inv = GetStoreInventory();

                    PackageInfo package;
                    try
                    {
                        package = inv.First(p => p.id == command.packageid);
                    }
                    catch
                    {
                        Dbgl($"Package {command.packageid} not found");
                        return;
                    }

                    PlayerInfo player = GetPlayerInfo(steamID.ToString());

                    if (player.currency < package.price)
                    {
                        Dbgl($"Player doesn't have enough currency {player.currency}, price {package.price}");
                        return;
                    }
                    player.currency -= package.price;
                    WritePlayerData(player);

                    JsonCommand sendCommand = new JsonCommand()
                    {
                        command  = "PurchaseResult",
                        currency = player.currency,
                        items    = GetPackageItems(package, player)
                    };


                    rpc.Invoke("SendServerRewardsJSON", new object[] { JsonUtility.ToJson(sendCommand) });
                }
                else if (command.command == "RequestStoreInfo")
                {
                    int currency = GetUserCurrency(steamID.ToString());
                    if (currency == -1)
                    {
                        Dbgl("Error getting store info");
                        return;
                    }

                    JsonCommand sendCommand = new JsonCommand()
                    {
                        command        = "SendStoreInfo",
                        storeTitle     = storeTitle.Value,
                        storeInventory = GetStoreInventoryString(),
                        currencyString = currencyString.Value,
                        currency       = currency,
                    };


                    rpc.Invoke("SendServerRewardsJSON", new object[] { JsonUtility.ToJson(sendCommand) });
                }
            }
            else
            {
                if (command.command == "PurchaseResult")
                {
                    myCurrency = command.currency;
                    foreach (string itemString in command.items.Split(';'))
                    {
                        Dbgl($"Receving {itemString}");

                        string[]   itemAmount = itemString.Split(',');
                        string     name       = itemAmount[0];
                        GameObject prefab     = ZNetScene.instance.GetPrefab(name);
                        if (!prefab)
                        {
                            Dbgl($"Item {name} not found!");
                            continue;
                        }

                        int amount = int.Parse(itemAmount[1]);
                        if (amount == 1)
                        {
                            Instantiate(prefab, Player.m_localPlayer.transform.position + Player.m_localPlayer.transform.forward * 2f + Vector3.up, Quaternion.identity);
                            Player.m_localPlayer.Message(MessageHud.MessageType.TopLeft, "Spawning object " + name, 0, null);
                        }
                        else
                        {
                            for (int j = 0; j < amount; j++)
                            {
                                Vector3 b = UnityEngine.Random.insideUnitSphere * 0.5f;
                                Instantiate(prefab, Player.m_localPlayer.transform.position + Player.m_localPlayer.transform.forward * 2f + Vector3.up + b, Quaternion.identity);
                                Player.m_localPlayer.Message(MessageHud.MessageType.TopLeft, "Spawning object " + name, 0, null);
                            }
                        }
                    }
                }
                else if (command.command == "SendStoreInfo")
                {
                    if (command.currency == -1)
                    {
                        Dbgl("Error getting store info");
                        return;
                    }
                    myCurrency           = command.currency;
                    windowTitleText      = command.storeTitle;
                    currencyString.Value = command.currencyString;
                    storePackages        = GetStorePackagesFromString(command.storeInventory);
                    Dbgl($"Got user currency: {myCurrency}");
                    if (Player.m_localPlayer)
                    {
                        Player.m_localPlayer.Message(MessageHud.MessageType.Center, $"You have {string.Format(command.currencyString, myCurrency)}");
                    }

                    storeOpen = true;
                }
            }
        }
Beispiel #26
0
        private static void RPC_SendJSON(ZRpc rpc, string json)
        {
            if (!modEnabled.Value)
            {
                return;
            }

            JsonCommand command = JsonUtility.FromJson <JsonCommand>(json);

            Dbgl($"RPC_SendJSON received command {command.command} {json} from id {command.id}");

            ZNetPeer peer    = Traverse.Create(ZNet.instance).Method("GetPeer", new object[] { rpc }).GetValue <ZNetPeer>();
            var      steamID = (peer.m_socket as ZSteamSocket).GetPeerID();

            if (ZNet.instance.IsServer())
            {
                context.UpdatePlayers(true);

                if (command.command == "BuyPackage")
                {
                    var packages = GetAllPackages();

                    PackageInfo package;
                    try
                    {
                        package = packages.First(p => p.id == command.packageid);
                    }
                    catch
                    {
                        Dbgl($"Package {command.packageid} not found");
                        return;
                    }

                    PlayerInfo player = GetPlayerInfo(steamID.ToString());

                    if (!CanBuyPackage(ref player, package, true, true, out string result))
                    {
                        WritePlayerData(player);
                        return;
                    }
                    Dbgl(result);

                    player.currency -= package.price;
                    WritePlayerData(player);

                    JsonCommand sendCommand = new JsonCommand()
                    {
                        command            = "PurchaseResult",
                        currency           = player.currency,
                        packageid          = package.id,
                        packagename        = package.name,
                        packagedescription = package.description,
                        items = GetPackageItems(package, player)
                    };

                    rpc.Invoke("SendServerRewardsJSON", new object[] { JsonUtility.ToJson(sendCommand) });
                }
                else if (command.command == "RequestStoreInfo")
                {
                    int currency = GetUserCurrency(steamID.ToString());
                    if (currency == -1)
                    {
                        Dbgl("Error getting store info");
                        return;
                    }
                    PlayerInfo player = GetPlayerInfo(steamID.ToString());

                    JsonCommand sendCommand = new JsonCommand()
                    {
                        command        = "SendStoreInfo",
                        storeTitle     = storeTitleString.Value,
                        storeInventory = GetStoreInventoryString(player),
                        currencyString = currencyString.Value,
                        currency       = currency,
                    };


                    rpc.Invoke("SendServerRewardsJSON", new object[] { JsonUtility.ToJson(sendCommand) });
                }
            }
            else
            {
                if (command.command == "PurchaseResult")
                {
                    Traverse.Create(GameCamera.instance).Field("m_mouseCapture").SetValue(true);
                    Cursor.lockState = CursorLockMode.Locked;
                    Cursor.visible   = false;
                    storeOpen        = false;
                    //PlayEffects();

                    var items = command.items.Split(';');

                    GameObject    chest         = null;
                    PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
                    Traverse      inventoryT    = null;

                    if (useTombstone.Value)
                    {
                        chest = Instantiate(Player.m_localPlayer.m_tombstone, Player.m_localPlayer.GetCenterPoint() + Player.m_localPlayer.transform.forward, Player.m_localPlayer.transform.rotation);
                        chest.GetComponent <Container>().m_name = command.packagename;
                        inventoryT = Traverse.Create(chest.GetComponent <Container>().GetInventory());
                        inventoryT.Field("m_name").SetValue(command.packagename);
                        inventoryT.Field("m_width").SetValue(8);
                        int rows = items.Count() / 8 + 2;
                        if (items.Count() % 8 != 0)
                        {
                            rows++;
                        }
                        inventoryT.Field("m_height").SetValue(rows);

                        TombStone tombstone = chest.GetComponent <TombStone>();
                        tombstone.Setup(command.packagename, playerProfile.GetPlayerID());
                    }

                    myCurrency = command.currency;

                    List <string> itemStrings = new List <string>();
                    foreach (string itemString in items)
                    {
                        Dbgl($"Receving {itemString}");

                        string[]   nameAmount = itemString.Split(',');
                        string     name       = nameAmount[0];
                        GameObject prefab     = ZNetScene.instance.GetPrefab(name);
                        if (!prefab)
                        {
                            Dbgl($"Item {name} not found!");
                            continue;
                        }

                        int amount = int.Parse(nameAmount[1]);

                        if (useTombstone.Value)
                        {
                            ItemDrop.ItemData item = prefab.GetComponent <ItemDrop>().m_itemData;

                            double slotsNeed = amount / item.m_shared.m_maxStackSize / 8;
                            inventoryT.Field("m_height").SetValue((int)inventoryT.Field("m_height").GetValue() + (int)Math.Round(slotsNeed, 0));
                            while (amount >= item.m_shared.m_maxStackSize)
                            {
                                int stack = Mathf.Min(item.m_shared.m_maxStackSize, amount);

                                //chest.GetComponent<Container>().GetInventory().AddItem(_newItem);
                                chest.GetComponent <Container>().GetInventory().AddItem(name, stack, item.m_quality, item.m_variant, Player.m_localPlayer.GetPlayerID(), Player.m_localPlayer.GetPlayerName());
                                amount = amount - stack;
                            }

                            if (amount > 0)
                            {
                                //chest.GetComponent<Container>().GetInventory().AddItem(_newItem2);
                                chest.GetComponent <Container>().GetInventory().AddItem(name, amount, item.m_quality, item.m_variant, Player.m_localPlayer.GetPlayerID(), Player.m_localPlayer.GetPlayerName());
                            }

                            itemStrings.Add($"{Localization.instance.Localize(item.m_shared.m_name)} {nameAmount[0]}");
                        }
                        else
                        {
                            if (amount == 1)
                            {
                                var go   = Instantiate(prefab, Player.m_localPlayer.transform.position + Player.m_localPlayer.transform.forward * 2f + Vector3.up, Quaternion.identity);
                                var item = go.GetComponent <ItemDrop>().m_itemData;
                                item.m_durability = item.m_shared.m_maxDurability;
                                Player.m_localPlayer.Message(MessageHud.MessageType.TopLeft, string.Format(rewardString.Value, Localization.instance.Localize(go.GetComponent <ItemDrop>().m_itemData.m_shared.m_name)), 0, null);
                            }
                            else
                            {
                                for (int j = 0; j < amount; j++)
                                {
                                    Vector3 b    = UnityEngine.Random.insideUnitSphere * 0.5f;
                                    var     go   = Instantiate(prefab, Player.m_localPlayer.transform.position + Player.m_localPlayer.transform.forward * 2f + Vector3.up + b, Quaternion.identity);
                                    var     item = go.GetComponent <ItemDrop>().m_itemData;
                                    item.m_durability = item.m_shared.m_maxDurability;
                                    Player.m_localPlayer.Message(MessageHud.MessageType.TopLeft, Localization.instance.Localize(go.GetComponent <ItemDrop>().m_itemData.m_shared.m_name), 0, null);
                                }
                            }
                        }
                    }
                    if (useTombstone.Value)
                    {
                        inventoryT.Method("Changed").GetValue();
                        chest.GetComponent <ZNetView>().GetZDO().Set("ServerReward", string.Format(packageInfoString.Value, command.packagename, playerProfile.GetName()) + "\r\n" + string.Join("\r\n", itemStrings));
                    }
                }
                else if (command.command == "SendStoreInfo")
                {
                    if (command.currency == -1)
                    {
                        Dbgl("Error getting store info");
                        return;
                    }
                    myCurrency           = command.currency;
                    windowTitleText      = command.storeTitle;
                    currencyString.Value = command.currencyString;
                    storePackages        = GetStorePackagesFromString(command.storeInventory);
                    Dbgl($"Got store inventory {storePackages.Count}, user currency: {myCurrency}");

                    storeOpen = true;
                }
                else if (command.command == "SendConsoleString")
                {
                    Traverse.Create(Console.instance).Method("AddString", new object[] { command.data }).GetValue();
                    Dbgl(command.data);
                }
            }
        }
Beispiel #27
0
        // Send server module list to client
        private static void ZNet_RPC_ServerHandshake(On.ZNet.orig_RPC_ServerHandshake orig, ZNet self, ZRpc rpc)
        {
            rpc.Invoke(nameof(RPC_Jotunn_ReceiveVersionData), new ModuleVersionData(GetEnforcableMods().ToList()).ToZPackage());

            orig(self, rpc);
        }
        private void WindowBuilder(int id)
        {
            GUI.DragWindow(new Rect(0, 0, windowWidth.Value, 20));
            GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(windowWidth.Value) });
            GUILayout.Label(windowTitleText, titleStyle);

            GUILayout.BeginHorizontal();
            GUILayout.Label(myCurrencyString.Value, currencyStyle);
            if (coinBeforeAmount.Value)
            {
                GUILayout.Space(5);
                GUILayout.Button(textureDict["currency"], coinStyle, new GUILayoutOption[] { GUILayout.Width(currencyFontSize.Value * coinFactor), GUILayout.Height(currencyFontSize.Value) });
            }
            GUILayout.Space(5);
            GUILayout.Label(string.Format(currencyString.Value, myCurrency), currencyStyle);
            if (!coinBeforeAmount.Value)
            {
                GUILayout.Space(5);
                GUILayout.Button(textureDict["currency"], coinStyle, new GUILayoutOption[] { GUILayout.Width(currencyFontSize.Value * coinFactor), GUILayout.Height(currencyFontSize.Value) });
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();

            float width     = windowWidth.Value - 70;
            float itemWidth = width / packagesPerRow.Value;

            scrollPosition = GUILayout.BeginScrollView(scrollPosition, new GUILayoutOption[] { GUILayout.Width(windowWidth.Value - 20) });
            GUILayout.Space(10);
            GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(width) });
            GUILayout.BeginHorizontal();
            storePackages.Sort(delegate(PackageInfo a, PackageInfo b) { return(a.price.CompareTo(b.price)); });
            for (int i = 0; i < storePackages.Count; i++)
            {
                if (i > 0 && i % packagesPerRow.Value == 0)
                {
                    GUILayout.EndHorizontal();
                    GUILayout.Space(10);
                    GUILayout.BeginHorizontal();
                }
                PackageInfo pi      = storePackages[i];
                string      texture = textureDict.ContainsKey(pi.type) ? pi.type : "Common";
                GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(itemWidth) });
                if (GUILayout.Button(new GUIContent(textureDict[texture], "This is a test"), new GUILayoutOption[] { GUILayout.Width(itemWidth), GUILayout.Height(itemWidth) }))
                {
                    if (myCurrency >= pi.price)
                    {
                        if (testing.Value)
                        {
                            myCurrency -= pi.price;
                            storeOpen   = false;
                            PlayEffects();
                        }
                        else
                        {
                            ZRpc serverRPC = ZNet.instance.GetServerRPC();
                            if (serverRPC != null)
                            {
                                Dbgl("Requesting store data");
                                JsonCommand command = new JsonCommand()
                                {
                                    command   = "BuyPackage",
                                    packageid = pi.id
                                };
                                string commandJson = JsonUtility.ToJson(command);
                                Dbgl(commandJson);
                                serverRPC.Invoke("SendServerRewardsJSON", new object[] { commandJson });
                            }
                        }
                    }
                }
                if (GUI.tooltip != null && GUI.tooltip.Length > 0)
                {
                    thisTooltip = GUI.tooltip;
                }

                GUILayout.Label(string.Format(packageString.Value, pi.name), labelStyle, new GUILayoutOption[] { GUILayout.Width(itemWidth) });
                GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Width(itemWidth) });
                GUILayout.FlexibleSpace();
                if (coinBeforeAmount.Value)
                {
                    GUILayout.Button(textureDict["currency"], coinStyle, new GUILayoutOption[] { GUILayout.Width(labelFontSize.Value * coinFactor), GUILayout.Height(labelFontSize.Value) });
                    GUILayout.Space(5);
                }
                GUILayout.Label(string.Format(currencyString.Value, pi.price), labelStyle);
                if (!coinBeforeAmount.Value)
                {
                    GUILayout.Space(5);
                    GUILayout.Button(textureDict["currency"], coinStyle, new GUILayoutOption[] { GUILayout.Width(labelFontSize.Value * coinFactor), GUILayout.Height(labelFontSize.Value) });
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
                GUILayout.EndVertical();
            }
            GUILayout.EndHorizontal();
            GUILayout.Space(10);
            GUILayout.EndVertical();
            GUILayout.EndScrollView();
            GUILayout.EndVertical();
        }
Beispiel #29
0
        //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 });
                }
            }
        }
Beispiel #30
0
        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);
        }