public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num)
        {
            //var data = Encoding.ASCII.GetString (readBuffer, num, length - 1);
            //var lines = data.Split ('\n');

            //foreach (var line in lines)
            //{
            //    if (line == "tdcm1")
            //    {
            //        //player.HasClientMod = true;
            //        ProgramLog.Log ("{0} is a TDCM protocol version 1 client.", conn.RemoteAddress);
            //    }
            //    else if (line == "tdsmcomp1")
            //    {
            //        conn.CompressionVersion = 1;
            //        ProgramLog.Log ("{0} supports TDSM compression version 1.", conn.RemoteAddress);
            //    }
            //}

            ReadString(readBuffer);

            var ctx = new HookContext
            {
                Connection = conn,
            };

            var args = new HookArgs.DisconnectReceived
            {
            };

            HookPoints.DisconnectReceived.Invoke(ref ctx, ref args);

            ctx.CheckForKick();
        }
        public override void Process(ClientConnection conn, byte[] readBuffer, int length, int num)
        {
            if (conn.State == SlotState.ACCEPTED)
            {
                SlotManager.Schedule(conn, conn.DesiredQueue);
                return;
            }

            int whoAmI = conn.SlotIndex;
            if (Terraria.Netplay.Clients[whoAmI].State() == SlotState.ASSIGNING_SLOT)
            {
                Terraria.Netplay.Clients[whoAmI].SetState(SlotState.SENDING_WORLD);
            }

            var ctx = new HookContext() { Connection = conn, Player = conn.Player };
            var args = new HookArgs.WorldRequestMessage()
            {
                SpawnX = Main.spawnTileX,
                SpawnY = Main.spawnTileY
            };
            HookPoints.WorldRequestMessage.Invoke(ref ctx, ref args);

            //NewNetMessage.SendData(7, whoAmI);
            var msg = NewNetMessage.PrepareThreadInstance();
            msg.WorldData(args.SpawnX, args.SpawnY);
            msg.Send(whoAmI);
        }
        public ClientConnection(Socket sock)
            : base(sock)
        {
            if (SlotId == 0)
                SlotId = -1;

            var remoteEndPoint = (IPEndPoint)sock.RemoteEndPoint;
            _remoteAddress = new TcpAddress(remoteEndPoint.Address, remoteEndPoint.Port);

            sock.LingerState = new LingerOption(true, 10);

            var ctx = new HookContext
            {
                Connection = this
            };

            var args = new HookArgs.NewConnection();

            HookPoints.NewConnection.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick())
                return;

            _isReceiving = true; //The connection was established, so we can begin reading
        }
        public void SetAuthentication(string auth, string by)
        {
            var ctx = new Plugin.HookContext()
            {
                Player     = this as Terraria.Player,
                Connection = this.Connection
            };
            var changing = new Plugin.HookArgs.PlayerAuthenticationChanging()
            {
                AuthenticatedAs = this.AuthenticatedAs,
                AuthenticatedBy = this.AuthenticatedBy
            };

            Plugin.HookPoints.PlayerAuthenticationChanging.Invoke(ref ctx, ref changing);
            if (ctx.Result != Plugin.HookResult.CONTINUE)
            {
                return;
            }

            this.AuthenticatedAs = auth;
            this.AuthenticatedBy = by;

            ctx = new Plugin.HookContext()
            {
                Player     = this as Terraria.Player,
                Connection = this.Connection
            };
            var changed = new Plugin.HookArgs.PlayerAuthenticationChanged()
            {
                AuthenticatedAs = this.AuthenticatedAs,
                AuthenticatedBy = this.AuthenticatedBy
            };

            Plugin.HookPoints.PlayerAuthenticationChanged.Invoke(ref ctx, ref changed);
        }
        public ClientConnection(Socket socket, int slot)
            : base(socket)
        {
            //var buf = NewNetMessage.buffer[id];
            //socket.SendBufferSize = 128000;
            connectedAt = time.Elapsed;

            if (slot >= 0) AssignSlot(slot);

            socket.LingerState = new LingerOption(true, 10);

            var ctx = new HookContext
            {
                Connection = this
            };

            var args = new HookArgs.NewConnection();

            HookPoints.NewConnection.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick())
                return;

            lock (All)
            {
                indexInAll = All.Count;
                All.Add(this);
            }

            StartReceiving(new byte[4192]);
        }
        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            //TODO [KillProjectileReceived]

            int identity = (int)ReadInt16(readBuffer);
            int playerId = (int)ReadByte(readBuffer);

            if (playerId != whoAmI && Entry.EnableCheatProtection)
            {
                Terraria.Netplay.Clients[whoAmI].Kick("Cheating detected (KILL_PROJECTILE forgery).");
                return;
            }

            var index = Tools.FindExistingProjectileForUser(whoAmI, identity);
            if (index == -1) return;

            var player = Main.player[whoAmI];

            var ctx = new HookContext
            {
                Connection = player.Connection,
                Player = player,
                Sender = player,
            };

            var args = new HookArgs.KillProjectileReceived
            {
                Id = identity,
                Owner = whoAmI,
                Index = index,
            };

            HookPoints.KillProjectileReceived.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick())
            {
                return;
            }

            if (ctx.Result == HookResult.IGNORE)
            {
                return;
            }

            if (ctx.Result == HookResult.RECTIFY)
            {
                var msg = NewNetMessage.PrepareThreadInstance();
                msg.Projectile(Main.projectile[index]);
                msg.Send(whoAmI);
                return;
            }

            var projectile = Main.projectile[index];

            if (projectile.owner == whoAmI && projectile.identity == identity)
            {
                projectile.Kill();
                NewNetMessage.SendData(29, -1, whoAmI, String.Empty, identity, (float)whoAmI);
            }
        }
        void OnReadConfig(ref HookContext ctx, ref HookArgs.ConfigurationLine args)
        {
            switch (args.Key)
            {
                case "mysql":
                    if (!Storage.IsAvailable)
                    {
                        MySQLConnector cn = null;

                        try
                        {
                            cn = new MySQLConnector(args.Value);
                            cn.Open();
                        }
                        catch (Exception e)
                        {
                            ProgramLog.Error.Log("Exception connecting to MySQL database: {0}", e);
                            return;
                        }
                        Storage.SetConnector(cn);

                        _connector = cn;
                    }
                    break;
            }
        }
 void OnStateChange(ref HookContext ctx, ref HookArgs.ServerStateChange args)
 {
     if (args.ServerChangeState == tdsm.api.ServerState.Initialising)
     {
         ProgramLog.Plugin.Log("MySQL connector is: " + (_connector == null ? "disabled" : "enabled"));
     }
 }
        public static bool OnProgramStarted(string[] cmd)
        {
            System.Threading.Thread.CurrentThread.Name = "Run";
            Console.OutputEncoding = System.Text.Encoding.UTF8;

            ProgramStart();
            #pragma warning disable 0162
            if (!Globals.FullAPIDefined)
            {
                Console.WriteLine("Your tdsm.api.dll is incorrect, and does not expose all methods.");
                return false;
            }
            #pragma warning restore 0162

            var ctx = new HookContext()
            {
                Sender = HookContext.ConsoleSender
            };
            var args = new HookArgs.ProgramStart()
            {
                Arguments = cmd
            };
            HookPoints.ProgramStart.Invoke(ref ctx, ref args);

            return ctx.Result == HookResult.DEFAULT;
        }
        public static void AddBan(int plr)
        {
            #if Full_API
            var ctx = new HookContext()
            {
                Sender = HookContext.ConsoleSender
            };
            var args = new HookArgs.AddBan()
            {
                RemoteAddress = Terraria.Netplay.Clients[plr].RemoteAddress()
            };

            HookPoints.AddBan.Invoke(ref ctx, ref args);

            if (ctx.Result == HookResult.DEFAULT)
            {
                string remote = Terraria.Netplay.Clients[plr].RemoteAddress();
                string ip = remote;
                for (int i = 0; i < remote.Length; i++)
                {
                    if (remote.Substring(i, 1) == ":")
                    {
                        ip = remote.Substring(0, i);
                    }
                }
                using (StreamWriter streamWriter = new StreamWriter(Terraria.Netplay.BanFilePath, true))
                {
                    streamWriter.WriteLine("//" + Terraria.Main.player[plr].name);
                    streamWriter.WriteLine(ip);
                }
            }
            #endif
        }
        public void SetAuthentication(string auth, string by)
        {
            var ctx = new Plugin.HookContext()
            {
                Player = this as Terraria.Player,
                Connection = this.Connection.Socket
            };
            var changing = new Plugin.HookArgs.PlayerAuthenticationChanging()
            {
                AuthenticatedAs = this.AuthenticatedAs,
                AuthenticatedBy = this.AuthenticatedBy
            };

            Plugin.HookPoints.PlayerAuthenticationChanging.Invoke(ref ctx, ref changing);
            if (ctx.Result != Plugin.HookResult.CONTINUE)
                return;

            this.AuthenticatedAs = auth;
            this.AuthenticatedBy = by;

            ctx = new Plugin.HookContext()
            {
                Player = this as Terraria.Player,
                Connection = this.Connection.Socket
            };
            var changed = new Plugin.HookArgs.PlayerAuthenticationChanged()
            {
                AuthenticatedAs = this.AuthenticatedAs,
                AuthenticatedBy = this.AuthenticatedBy
            };

            Plugin.HookPoints.PlayerAuthenticationChanged.Invoke(ref ctx, ref changed);
        }
        public static bool OnGreetPlayer(int playerId)
        {
            var player = Main.player[playerId];

            var ctx = new HookContext
            {
                Connection = player.Connection.Socket,
                Player = player,
                Sender = player,
            };

            var args = new HookArgs.PlayerPreGreeting
            {
                Slot = playerId,
                Motd = String.IsNullOrEmpty(Main.motd) ? (Lang.mp[18] + " " + Main.worldName) : Main.motd,
                MotdColour = new Microsoft.Xna.Framework.Color(255, 240, 20)
            };

            HookPoints.PlayerPreGreeting.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick())
            {
                return false;
            }

            player.SendMessage(args.Motd, 255, args.MotdColour.R, args.MotdColour.G, args.MotdColour.B);

            string list = "";
            for (int i = 0; i < 255; i++)
            {
                if (Main.player[i].active)
                {
                    if (list == "")
                        list += Main.player[i].name;
                    else
                        list = list + ", " + Main.player[i].Name;
                }
            }

            player.SendMessage("Current players: " + list + ".", 255, 255, 240, 20);

            Tools.WriteLine("{0} @ {1}: ENTER {2}", Netplay.Clients[playerId].Socket.GetRemoteAddress(), playerId, player.name);

            var args2 = new HookArgs.PlayerEnteredGame
            {
                Slot = playerId
            };

            ctx.SetResult(HookResult.DEFAULT, false);
            HookPoints.PlayerEnteredGame.Invoke(ref ctx, ref args2);
            ctx.CheckForKick();

            return false; //We implemented our own, so do not continue on with vanilla
        }
        public static void OnInvasionNPCSpawn(int x, int y)
        {
            var ctx = new HookContext();
            var args = new HookArgs.InvasionNPCSpawn()
            {
                X = x,
                Y = y
            };

            HookPoints.InvasionNPCSpawn.Invoke(ref ctx, ref args);
        }
        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            int x = ReadInt16(readBuffer);
            int y = ReadInt16(readBuffer);

            var player = Main.player[whoAmI];

            if (Math.Abs(player.position.X / 16 - x) >= 7 || Math.Abs(player.position.Y / 16 - y) >= 7)
            {
                return;
            }

            int chestIndex = Chest.FindChest(x, y);

            var ctx = new HookContext
            {
                Connection = player.Connection,
                Player = player,
                Sender = player,
            };

            var args = new HookArgs.ChestOpenReceived
            {
                X = x,
                Y = y,
                ChestIndex = chestIndex,
            };

            HookPoints.ChestOpenReceived.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick())
            {
                return;
            }

            if (ctx.Result == HookResult.IGNORE)
            {
                return;
            }

            if (ctx.Result == HookResult.DEFAULT && chestIndex > -1)
            {
                var user = Chest.UsingChest(chestIndex);
                if (user >= 0 && user != whoAmI) return;

                for (int i = 0; i < Chest.maxItems; i++)
                {
                    NewNetMessage.SendData(32, whoAmI, -1, String.Empty, chestIndex, (float)i);
                }
                NewNetMessage.SendData(33, whoAmI, -1, String.Empty, chestIndex);
                Main.player[whoAmI].chest = chestIndex;
                return;
            }
        }
        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            int playerIndex = ReadByte(readBuffer);

            if (playerIndex != whoAmI && Entry.EnableCheatProtection)
            {
                Terraria.Netplay.Clients[whoAmI].Kick("Cheating detected (PLAYER_PVP_CHANGE forgery).");
                return;
            }

            var pvp = ReadByte(readBuffer) == 1;
            var player = Main.player[whoAmI];

            var ctx = new HookContext
            {
                Connection = player.Connection,
                Player = player,
                Sender = player,
            };

            var args = new HookArgs.PvpSettingReceived
            {
                PvpFlag = pvp,
            };

            HookPoints.PvpSettingReceived.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick())
            {
                return;
            }

            if (ctx.Result == HookResult.IGNORE)
            {
                return;
            }

            if (ctx.Result == HookResult.RECTIFY)
            {
                NewNetMessage.SendData(30, whoAmI, -1, String.Empty, whoAmI);
                return;
            }

            player.hostile = pvp;

            string message = (player.hostile) ? " has enabled PvP!" : " has disabled PvP!";

            NewNetMessage.SendData(30, -1, whoAmI, String.Empty, whoAmI);
            NewNetMessage.SendData(25, -1, -1, player.Name + message, 255, (float)Main.teamColor[player.team].R, (float)Main.teamColor[player.team].G, (float)Main.teamColor[player.team].B);
        }
        public static bool CanSpawnNPC(int x, int y, int type, int start = 0)
        {
            var ctx = new HookContext();
            var args = new HookArgs.NPCSpawn()
            {
                X = x,
                Y = y,
                Type = type,
                Start = start
            };

            HookPoints.NPCSpawn.Invoke(ref ctx, ref args);

            return ctx.Result == HookResult.DEFAULT;
        }
        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            int start = num - 1;
            int playerIndex = ReadByte(readBuffer);

            if (playerIndex != whoAmI && Entry.EnableCheatProtection)
            {
                Terraria.Netplay.Clients[whoAmI].Kick("Cheating detected (KILL_PLAYER forgery).");
                return;
            }

            var player = Main.player[whoAmI];

            var ctx = new HookContext
            {
                Connection = (Terraria.Netplay.Clients[whoAmI] as ServerSlot).conn,
                Sender = player,
                Player = player,
            };

            var args = new HookArgs.ObituaryReceived
            {
                Direction = (int)ReadByte(readBuffer) - 1,
                Damage = ReadInt16(readBuffer),
                PvpFlag = ReadByte(readBuffer)
            };
            //string obituary;
            //if (!ParseString(readBuffer, num + 1, length - num - 1 + start, out obituary))
            //{
            //    tdsm.api.Callbacks.Netplay.slots[whoAmI].Kick("Invalid characters in obituary message.");
            //    return;
            //}
            args.Obituary = " " + ReadString(readBuffer);

            HookPoints.ObituaryReceived.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick())
                return;

            if (ctx.Result == HookResult.IGNORE)
                return;

            ProgramLog.Log("{0} @ {1}: [Death] {2}{3}", player.IPAddress, whoAmI, player.Name ?? "<null>", args.Obituary);

            player.KillMe(args.Damage, args.Direction, args.PvpFlag == 1, args.Obituary);

            NewNetMessage.SendData(44, -1, whoAmI, args.Obituary, whoAmI, args.Direction, args.Damage, args.PvpFlag);
        }
 public static void Initialise()
 {
     #if Full_API
     if (Terraria.Main.dedServ)
     {
         var ctx = new HookContext()
         {
             Sender = HookContext.ConsoleSender
         };
         var args = new HookArgs.ServerStateChange()
         {
             ServerChangeState = ServerState.Initialising
         };
         HookPoints.ServerStateChange.Invoke(ref ctx, ref args);
     }
     #endif
 }
        public static void OnPlayerEntering(Player player)
        {
            var ctx = new HookContext
            {
                Player = player,
                Sender = player
            };

            var args = new HookArgs.PlayerEnteringGame
            {
                Slot = player.whoAmI
            };

            ctx.SetResult(HookResult.DEFAULT, false);
            HookPoints.PlayerEnteringGame.Invoke(ref ctx, ref args);
            ctx.CheckForKick();
        }
        void OnReadConfig(ref HookContext ctx, ref HookArgs.ConfigurationLine args)
        {
            switch (args.Key)
            {
                case "sqlite":
                    if (_connector == null)
                    {
                        var cn = new SQLiteConnector(args.Value);

                        cn.Open();

                        Storage.SetConnector(cn);

                        _connector = cn;
                    }
                    break;
            }
        }
        //TODO: redesign signs
        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            int start = num - 1;
            short signIndex = ReadInt16(readBuffer);
            int x = ReadInt16(readBuffer);
            int y = ReadInt16(readBuffer);

            short existing = (short)Sign.ReadSign(x, y);
            if (existing >= 0)
                signIndex = existing;

            //string SignText;
            //if (!ParseString(readBuffer, num, length - num + start, out SignText))
            //    return; // invalid characters
            var SignText = ReadString(readBuffer);

            var player = Main.player[whoAmI];

            var ctx = new HookContext
            {
                Connection = player.Connection,
                Sender = player,
                Player = player,
            };

            var args = new HookArgs.SignTextSet
            {
                X = x,
                Y = y,
                SignIndex = signIndex,
                Text = SignText,
                OldSign = Main.sign[signIndex],
            };

            HookPoints.SignTextSet.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick() || ctx.Result == HookResult.IGNORE)
                return;

            if (Main.sign[signIndex] == null) Main.sign[signIndex] = new Sign();
            Main.sign[signIndex].x = args.X;
            Main.sign[signIndex].y = args.Y;
            Sign.TextSign(signIndex, args.Text);
        }
        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            int playerId = ReadByte(readBuffer);
            byte action = ReadByte(readBuffer);

            if (playerId != whoAmI && Entry.EnableCheatProtection)
            {
                Terraria.Netplay.Clients[whoAmI].Kick("SummonSkeletron Player Forgery.");
                return;
            }

            if (action == 1)
            {
                var player = Main.player[whoAmI];

                var ctx = new HookContext
                {
                    Connection = player.Connection,
                    Sender = player,
                    Player = player,
                };

                var args = new HookArgs.PlayerTriggeredEvent
                {
                    Type = WorldEventType.BOSS,
                    Name = "Skeletron",
                };

                HookPoints.PlayerTriggeredEvent.Invoke(ref ctx, ref args);

                if (ctx.CheckForKick() || ctx.Result == HookResult.IGNORE)
                    return;

                //ProgramLog.Users.Log ("{0} @ {1}: Skeletron summoned by {2}.", player.IPAddress, whoAmI, player.Name);
                //NewNetMessage.SendData (Packet.PLAYER_CHAT, -1, -1, string.Concat (player.Name, " has summoned Skeletron!"), 255, 255, 128, 150);
                NPC.SpawnSkeletron();
            }
            else if (action == 2)
            {
                NewNetMessage.SendData(51, -1, whoAmI, String.Empty, playerId, action, 0f, 0f, 0);
            }
        }
        public static bool Initialise()
        {
            #if Full_API
            if (Terraria.Main.dedServ)
            {
                var ctx = new HookContext()
                {
                    Sender = HookContext.ConsoleSender
                };
                var args = new HookArgs.ServerStateChange()
                {
                    ServerChangeState = ServerState.Starting
                };
                HookPoints.ServerStateChange.Invoke(ref ctx, ref args);

                return ctx.Result != HookResult.IGNORE;
            }
            #endif

            return true; //Allow continue
        }
 public static bool SendData(int msgType, int remoteClient = -1, int ignoreClient = -1, string text = "", int number = 0, float number2 = 0f, float number3 = 0f, float number4 = 0f, int number5 = 0)
 {
     var ctx = new HookContext()
     {
         Sender = HookContext.ConsoleSender
     };
     var args = new HookArgs.SendNetData()
     {
         MsgType = msgType,
         RemoteClient = remoteClient,
         IgnoreClient = ignoreClient,
         Text = text,
         Number = number,
         Number2 = number2,
         Number3 = number3,
         Number4 = number4,
         Number5 = number5
     };
     HookPoints.SendNetData.Invoke(ref ctx, ref args);
     return ctx.Result == HookResult.DEFAULT;
 }
        public override void Process(int whoAmI, byte[] readBuffer, int length, int num)
        {
            int x = (int)ReadInt16(readBuffer);
            int y = (int)ReadInt16(readBuffer);

            int signIndex = Sign.ReadSign(x, y);

            var player = Main.player[whoAmI];

            var ctx = new HookContext
            {
                Connection = player.Connection,
                Sender = player,
                Player = player,
            };

            var args = new HookArgs.SignTextGet
            {
                X = x,
                Y = y,
                SignIndex = (short)signIndex,
                Text = (signIndex >= 0 && Main.sign[signIndex] != null) ? Main.sign[signIndex].text : null,
            };

            HookPoints.SignTextGet.Invoke(ref ctx, ref args);

            if (ctx.CheckForKick() || ctx.Result == HookResult.IGNORE)
                return;

            if (args.Text != null)
            {
                var msg = NewNetMessage.PrepareThreadInstance();
                msg.WriteSign(signIndex, x, y, args.Text);
                msg.Send(whoAmI);
            }
        }
        void OnStartCommandProcessing(ref HookContext ctx, ref HookArgs.StartCommandProcessing args)
        {
            ctx.SetResult(HookResult.IGNORE);

            (new tdsm.api.Misc.ProgramThread("Command", ListenForCommands)).Start();
        }
        void OnServerStateChange(ref HookContext ctx, ref HookArgs.ServerStateChange args)
        {
            ProgramLog.Log("Server state changed to: " + args.ServerChangeState.ToString());

            if (args.ServerChangeState == ServerState.Initialising)
            {
                if (!String.IsNullOrEmpty(RConBindAddress))
                {
                    ProgramLog.Log("Starting RCON Server");
                    RemoteConsole.RConServer.Start(Path.Combine(Globals.DataPath, "rcon_logins.properties"));
                }
            }
            if (args.ServerChangeState == ServerState.Stopping)
            {
                RemoteConsole.RConServer.Stop();
            }

            //if (args.ServerChangeState == ServerState.Initialising)
            #if TDSMServer
            if (!Server.IsInitialised)
            {
                Server.Init();

                if (!String.IsNullOrEmpty(RConBindAddress))
                {
                    ProgramLog.Log("Starting RCON Server");
                    RemoteConsole.RConServer.Start(Path.Combine(Globals.DataPath, "rcon_logins.properties"));
                }

                if (!String.IsNullOrEmpty(_webServerAddress))
                {
                    ProgramLog.Log("Starting Web Server");
                    WebInterface.WebServer.Begin(_webServerAddress, _webServerProvider);

                    AddCommand("webauth")
                        .WithAccessLevel(AccessLevel.OP)
                        .Calls(WebInterface.WebServer.WebAuthCommand);
                }
            }

            if (args.ServerChangeState == ServerState.Stopping)
            {
                RemoteConsole.RConServer.Stop();
                WebInterface.WebServer.End();
                //if (properties != null && File.Exists(properties.PIDFile.Trim()))
                //File.Delete(properties.PIDFile.Trim());
            }

            ctx.SetResult(HookResult.IGNORE); //Don't continue on with vanilla code
            #endif
        }
 void OnPlayerJoin(ref HookContext ctx, ref HookArgs.PlayerEnteredGame args)
 {
     //The player may randomly disconnect at any time, and if it's before the point of saving then the data may be lost.
     //So we must ensure the data is saved.
     //ServerCharacters.CharacterManager.EnsureSave = true;
 }
 void OnPlayerDisconnected(ref HookContext ctx, ref HookArgs.PlayerLeftGame args)
 {
     #if TDSMServer
     if (RestartWhenNoPlayers && ClientConnection.All.Count - 1 == 0)
     {
         PerformRestart();
     }
     #endif
 }
 void OnNPCSpawned(ref HookContext ctx, ref HookArgs.NPCSpawn args)
 {
     if (StopNPCSpawning)
         ctx.SetResult(HookResult.IGNORE);
 }
 void OnInventoryItemReceived(ref HookContext ctx, ref HookArgs.InventoryItemReceived args)
 {
     #if TDSMSever
     if (Server.ItemRejections.Count > 0)
     {
         if (args.Item != null)
         {
             if (Server.ItemRejections.Contains(args.Item.name) || Server.ItemRejections.Contains(args.Item.type.ToString()))
             {
                 if (!String.IsNullOrEmpty(args.Item.name))
                 {
                     ctx.SetKick(args.Item.name + " is not allowed on this server.");
                 }
                 else
                 {
                     ctx.SetKick("Item type " + args.Item.type.ToString() + " is not allowed on this server.");
                 }
             }
         }
     }
     #endif
 }