Merge branch 'master' of github.com:TShock/TShock into sql

This commit is contained in:
high 2011-06-16 10:49:09 -04:00
commit bde8bc8bf2
10 changed files with 1243 additions and 1158 deletions

View file

@ -74,6 +74,7 @@ namespace TShockAPI
public void RemoveBan(Ban ban) public void RemoveBan(Ban ban)
{ {
Bans.Remove(ban); Bans.Remove(ban);
SaveBans();
} }
/// <summary> /// <summary>

File diff suppressed because it is too large Load diff

View file

@ -66,6 +66,8 @@ namespace TShockAPI
if (File.Exists(ConfigPath)) if (File.Exists(ConfigPath))
{ {
ConfigurationManager.ReadJsonConfiguration(); ConfigurationManager.ReadJsonConfiguration();
// Add all the missing config properties in the json file
ConfigurationManager.WriteJsonConfiguration();
} }
else else
{ {

426
TShockAPI/GetDataHandlers.cs Executable file
View file

@ -0,0 +1,426 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011 The TShock Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Microsoft.Xna.Framework;
using StreamBinary;
using Terraria;
using TerrariaAPI;
namespace TShockAPI
{
public delegate bool GetDataHandlerDelegate(GetDataHandlerArgs args);
public class GetDataHandlerArgs : EventArgs
{
public TSPlayer Player { get; private set; }
public MemoryStream Data { get; private set; }
public Player TPlayer
{
get { return Player.TPlayer; }
}
public GetDataHandlerArgs(TSPlayer player, MemoryStream data)
{
Player = player;
Data = data;
}
}
public static class GetDataHandlers
{
private static Dictionary<PacketTypes, GetDataHandlerDelegate> GetDataHandlerDelegates;
private static bool[] BlacklistTiles;
public static void InitGetDataHandler()
{
#region Blacklisted tiles
BlacklistTiles = new bool[Main.maxTileSets];
BlacklistTiles[0] = true;
BlacklistTiles[1] = true;
BlacklistTiles[2] = true;
BlacklistTiles[6] = true;
BlacklistTiles[7] = true;
BlacklistTiles[8] = true;
BlacklistTiles[9] = true;
BlacklistTiles[22] = true;
BlacklistTiles[23] = true;
BlacklistTiles[25] = true;
BlacklistTiles[30] = true;
BlacklistTiles[37] = true;
BlacklistTiles[38] = true;
BlacklistTiles[39] = true;
BlacklistTiles[40] = true;
BlacklistTiles[41] = true;
BlacklistTiles[43] = true;
BlacklistTiles[44] = true;
BlacklistTiles[45] = true;
BlacklistTiles[46] = true;
BlacklistTiles[47] = true;
BlacklistTiles[53] = true;
BlacklistTiles[54] = true;
BlacklistTiles[56] = true;
BlacklistTiles[57] = true;
BlacklistTiles[58] = true;
BlacklistTiles[59] = true;
BlacklistTiles[60] = true;
BlacklistTiles[63] = true;
BlacklistTiles[64] = true;
BlacklistTiles[65] = true;
BlacklistTiles[66] = true;
BlacklistTiles[67] = true;
BlacklistTiles[68] = true;
BlacklistTiles[70] = true;
BlacklistTiles[75] = true;
BlacklistTiles[76] = true;
#endregion Blacklisted tiles
GetDataHandlerDelegates = new Dictionary<PacketTypes, GetDataHandlerDelegate>
{
{PacketTypes.PlayerInfo, HandlePlayerInfo},
{PacketTypes.TileSendSection, HandleSendSection},
{PacketTypes.PlayerUpdate, HandlePlayerUpdate},
{PacketTypes.Tile, HandleTile},
{PacketTypes.TileSendSquare, HandleSendTileSquare},
{PacketTypes.NPCUpdate, HandleNpcUpdate},
{PacketTypes.PlayerDamage, HandlePlayerDamage},
{PacketTypes.ProjectileNew, HandleProjectileNew},
{PacketTypes.TogglePVP, HandleTogglePvp},
{PacketTypes.TileKill, HandleTileKill},
{PacketTypes.PlayerKillMe, HandlePlayerKillMe},
{PacketTypes.LiquidSet, HandleLiquidSet},
};
}
public static bool HandlerGetData(PacketTypes type, TSPlayer player, MemoryStream data)
{
GetDataHandlerDelegate handler;
if (GetDataHandlerDelegates.TryGetValue(type, out handler))
{
try
{
return handler(new GetDataHandlerArgs(player, data));
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
return false;
}
private static bool HandlePlayerInfo(GetDataHandlerArgs args)
{
byte playerid = args.Data.ReadInt8();
byte hair = args.Data.ReadInt8();
Color hairColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8());
Color skinColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8());
Color eyeColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8());
Color shirtColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8());
Color underShirtColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8());
Color pantsColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8());
Color shoeColor = new Color(args.Data.ReadInt8(), args.Data.ReadInt8(), args.Data.ReadInt8());
string name = Encoding.ASCII.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1)));
if (hair >= Main.maxHair)
{
Tools.ForceKick(args.Player, "Hair crash exploit.");
return true;
}
if (name.Length > 32)
{
Tools.ForceKick(args.Player, "Name exceeded 32 characters.");
return true;
}
if (name.Trim().Length == 0)
{
Tools.ForceKick(args.Player, "Empty Name.");
return true;
}
var ban = TShock.Bans.GetBanByName(name);
if (ban != null)
{
Tools.ForceKick(args.Player, string.Format("You are banned: {0}", ban.Reason));
return true;
}
if (args.Player.ReceivedInfo)
{
return Tools.HandleGriefer(args.Player, "Sent client info more than once");
}
args.Player.ReceivedInfo = true;
return false;
}
private static bool HandleSendTileSquare(GetDataHandlerArgs args)
{
short size = args.Data.ReadInt16();
int x = args.Data.ReadInt32();
int y = args.Data.ReadInt32();
int plyX = Math.Abs(args.Player.TileX);
int plyY = Math.Abs(args.Player.TileY);
int tileX = Math.Abs(x);
int tileY = Math.Abs(y);
if (size > 5 || (ConfigurationManager.RangeChecks && (Math.Abs(plyX - tileX) > 32 || Math.Abs(plyY - tileY) > 32)))
{
Log.Debug(string.Format("SendTileSquare(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Size:{6})",
plyX, plyY, tileX, tileY, Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), size));
return Tools.HandleGriefer(args.Player, "Send Tile Square Abuse");
}
return false;
}
private static bool HandleTile(GetDataHandlerArgs args)
{
byte type = args.Data.ReadInt8();
int x = args.Data.ReadInt32();
int y = args.Data.ReadInt32();
byte tiletype = args.Data.ReadInt8();
if (type == 1 || type == 3)
{
int plyX = Math.Abs(args.Player.TileX);
int plyY = Math.Abs(args.Player.TileY);
int tileX = Math.Abs(x);
int tileY = Math.Abs(y);
if (ConfigurationManager.RangeChecks && ((Math.Abs(plyX - tileX) > 32) || (Math.Abs(plyY - tileY) > 32)))
{
Log.Debug(string.Format("TilePlaced(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Type:{6})",
plyX, plyY, tileX, tileY, Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), tiletype));
return Tools.HandleGriefer(args.Player, "Placing impossible to place blocks.");
}
}
if (ConfigurationManager.DisableBuild)
{
if (!args.Player.Group.HasPermission("editspawn"))
{
args.Player.SendMessage("World protected from changes.", Color.Red);
TShock.SendTileSquare(args.Player, x, y);
return true;
}
}
if (ConfigurationManager.SpawnProtect)
{
if (!args.Player.Group.HasPermission("editspawn"))
{
var flag = TShock.CheckSpawn(x, y);
if (flag)
{
args.Player.SendMessage("Spawn protected from changes.", Color.Red);
TShock.SendTileSquare(args.Player, x, y);
return true;
}
}
}
if (type == 0 && BlacklistTiles[Main.tile[x, y].type] && args.Player.Active)
{
args.Player.TileThreshold++;
var coords = new Vector2(x, y);
if (!args.Player.TilesDestroyed.ContainsKey(coords))
args.Player.TilesDestroyed.Add(coords, Main.tile[x, y]);
}
return false;
}
private static bool HandleTogglePvp(GetDataHandlerArgs args)
{
int id = args.Data.ReadByte();
bool pvp = args.Data.ReadBoolean();
args.TPlayer.hostile = pvp;
if (id != args.Player.Index)
args.TPlayer.hostile = true;
if (ConfigurationManager.PermaPvp)
args.TPlayer.hostile = true;
NetMessage.SendData(30, -1, -1, "", args.Player.Index);
return true;
}
private static bool HandleSendSection(GetDataHandlerArgs args)
{
return Tools.HandleGriefer(args.Player, "SendSection abuse.");
}
private static bool HandleNpcUpdate(GetDataHandlerArgs args)
{
return Tools.HandleGriefer(args.Player, "Spawn NPC abuse");
}
private static bool HandlePlayerUpdate(GetDataHandlerArgs args)
{
byte plr = args.Data.ReadInt8();
byte control = args.Data.ReadInt8();
byte item = args.Data.ReadInt8();
float posx = args.Data.ReadSingle();
float posy = args.Data.ReadSingle();
float velx = args.Data.ReadSingle();
float vely = args.Data.ReadSingle();
if (Main.verboseNetplay)
Debug.WriteLine("Update: {{{0},{1}}} {{{2}, {3}}}", (int)posx, (int)posy, (int)velx, (int)vely);
if (plr != args.Player.Index)
{
return Tools.HandleGriefer(args.Player, "Update Player abuse");
}
return false;
}
private static bool HandleProjectileNew(GetDataHandlerArgs args)
{
short ident = args.Data.ReadInt16();
float posx = args.Data.ReadSingle();
float posy = args.Data.ReadSingle();
float velx = args.Data.ReadSingle();
float vely = args.Data.ReadSingle();
float knockback = args.Data.ReadSingle();
short dmg = args.Data.ReadInt16();
byte owner = args.Data.ReadInt8();
byte type = args.Data.ReadInt8();
if (type == 29 || type == 28 || type == 37)
{
Log.Debug(string.Format("Explosive(PlyXY:{0}_{1}, Type:{2})", args.Player.TileX, args.Player.TileY, type));
return Tools.HandleExplosivesUser(args.Player, "Throwing an explosive device.");
}
return false;
}
private static bool HandlePlayerKillMe(GetDataHandlerArgs args)
{
byte id = args.Data.ReadInt8();
byte hitdirection = args.Data.ReadInt8();
short dmg = args.Data.ReadInt16();
bool pvp = args.Data.ReadBoolean();
if (id != args.Player.Index)
{
return Tools.HandleGriefer(args.Player, "Trying to execute KillMe on someone else.");
}
return false;
}
private static bool HandlePlayerDamage(GetDataHandlerArgs args)
{
byte playerid = args.Data.ReadInt8();
byte direction = args.Data.ReadInt8();
Int16 damage = args.Data.ReadInt16();
byte pvp = args.Data.ReadInt8();
return !TShock.Players[playerid].TPlayer.hostile;
}
private static bool HandleLiquidSet(GetDataHandlerArgs args)
{
int x = args.Data.ReadInt32();
int y = args.Data.ReadInt32();
byte liquid = args.Data.ReadInt8();
bool lava = args.Data.ReadBoolean();
//The liquid was picked up.
if (liquid == 0)
return false;
int plyX = Math.Abs(args.Player.TileX);
int plyY = Math.Abs(args.Player.TileY);
int tileX = Math.Abs(x);
int tileY = Math.Abs(y);
bool bucket = false;
for (int i = 0; i < 44; i++)
{
if (args.TPlayer.inventory[i].type >= 205 && args.TPlayer.inventory[i].type <= 207)
{
bucket = true;
break;
}
}
if (lava && !args.Player.Group.HasPermission("canlava"))
{
args.Player.SendMessage("You do not have permission to use lava", Color.Red);
Tools.SendLogs(string.Format("{0} tried using lava", args.Player.Name), Color.Red);
// TODO need to revert player changes so they are insync with server
return true;
}
if (!lava && !args.Player.Group.HasPermission("canwater"))
{
args.Player.SendMessage("You do not have permission to use water", Color.Red);
Tools.SendLogs(string.Format("{0} tried using water", args.Player.Name), Color.Red);
// TODO need to revert player changes so they are insync with server
return true;
}
if (!bucket)
{
Log.Debug(string.Format("{0}(PlyXY:{1}_{2}, TileXY:{3}_{4}, Result:{5}_{6}, Amount:{7})",
lava ? "Lava" : "Water", plyX, plyY, tileX, tileY,
Math.Abs(plyX - tileX), Math.Abs(plyY - tileY), liquid));
return Tools.HandleGriefer(args.Player, "Manipulating liquid without bucket."); ;
}
if (ConfigurationManager.RangeChecks && ((Math.Abs(plyX - tileX) > 32) || (Math.Abs(plyY - tileY) > 32)))
{
Log.Debug(string.Format("Liquid(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Amount:{6})",
plyX, plyY,
tileX, tileY,
Math.Abs(plyX - tileX), Math.Abs(plyY - tileY),
liquid
));
return Tools.HandleGriefer(args.Player, "Placing impossible to place liquid."); ;
}
if (ConfigurationManager.SpawnProtect)
{
if (!args.Player.Group.HasPermission("editspawn"))
{
var flag = TShock.CheckSpawn(x, y);
if (flag)
{
args.Player.SendMessage("The spawn is protected!", Color.Red);
// TODO need to revert player changes so they are insync with server
return true;
}
}
}
return false;
}
private static bool HandleTileKill(GetDataHandlerArgs args)
{
int tilex = args.Data.ReadInt32();
int tiley = args.Data.ReadInt32();
if (tilex < 0 || tilex >= Main.maxTilesX || tiley < 0 || tiley >= Main.maxTilesY)
return false;
if (Main.tile[tilex, tiley].type != 0x15) //Chest
{
Log.Debug(string.Format("TileKill(TileXY:{0}_{1}, Type:{2})",
tilex, tiley, Main.tile[tilex, tiley].type));
Tools.ForceKick(args.Player, string.Format("Tile Kill abuse ({0})", Main.tile[tilex, tiley].type));
return true;
}
return false;
}
}
}

View file

@ -1,19 +1,19 @@
/* /*
TShock, a server mod for Terraria TShock, a server mod for Terraria
Copyright (C) 2011 The TShock Team Copyright (C) 2011 The TShock Team
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -33,19 +33,28 @@ namespace TShockAPI
public Group Group { get; set; } public Group Group { get; set; }
public bool ReceivedInfo { get; set; } public bool ReceivedInfo { get; set; }
public int Index { get; protected set; } public int Index { get; protected set; }
public bool RealPlayer
{
get { return Index >= 0 && Index < Main.maxNetPlayers; }
}
public bool ConnectionAlive
{
get { return RealPlayer ? Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill : false; }
}
/// <summary> /// <summary>
/// Terraria Player /// Terraria Player
/// </summary> /// </summary>
public Player TPlayer { get; protected set; } public Player TPlayer { get; protected set; }
public string Name public string Name
{ {
get { return TPlayer.name; } get { return TPlayer.name; }
} }
public string IP public string IP
{ {
get { return Tools.GetRealIP(Netplay.serverSock[Index].tcpClient.Client.RemoteEndPoint.ToString()); } get
{
return RealPlayer ? Tools.GetRealIP(Netplay.serverSock[Index].tcpClient.Client.RemoteEndPoint.ToString()) : "";
}
} }
public bool Active public bool Active
{ {
@ -55,14 +64,20 @@ namespace TShockAPI
{ {
get { return TPlayer.team; } get { return TPlayer.team; }
} }
public float X public float X
{ {
get { return TPlayer.position.X; } get
{
return RealPlayer ? TPlayer.position.X : Main.spawnTileX * 16;
}
} }
public float Y public float Y
{ {
get { return TPlayer.position.Y; } get
{
return RealPlayer ? TPlayer.position.Y : Main.spawnTileY * 16;
}
} }
public int TileX public int TileX
{ {
@ -70,7 +85,7 @@ namespace TShockAPI
} }
public int TileY public int TileY
{ {
get { return (int)(X / 16); } get { return (int)(Y / 16); }
} }
public TSPlayer(int index) public TSPlayer(int index)

View file

@ -20,10 +20,8 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Content;
using StreamBinary;
using Terraria; using Terraria;
using TerrariaAPI; using TerrariaAPI;
using TerrariaAPI.Hooks; using TerrariaAPI.Hooks;
@ -41,13 +39,8 @@ namespace TShockAPI
public static readonly string VersionCodename = "Forgot to increase the version."; public static readonly string VersionCodename = "Forgot to increase the version.";
private static bool[] BlacklistTiles;
public static BanManager Bans = new BanManager(Path.Combine(SavePath, "bans.txt")); public static BanManager Bans = new BanManager(Path.Combine(SavePath, "bans.txt"));
delegate bool HandleGetDataD(MemoryStream data, GetDataEventArgs e);
Dictionary<byte, HandleGetDataD> GetDataFuncs;
public override Version Version public override Version Version
{ {
get { return VersionNum; } get { return VersionNum; }
@ -68,85 +61,15 @@ namespace TShockAPI
get { return "The administration modification of the future."; } get { return "The administration modification of the future."; }
} }
static TShock()
{
//Tools.LoadGroups();
#region Blacklisted tiles
BlacklistTiles = new bool[0x80];
BlacklistTiles[0] = true;
BlacklistTiles[1] = true;
BlacklistTiles[2] = true;
BlacklistTiles[6] = true;
BlacklistTiles[7] = true;
BlacklistTiles[8] = true;
BlacklistTiles[9] = true;
BlacklistTiles[22] = true;
BlacklistTiles[23] = true;
BlacklistTiles[25] = true;
BlacklistTiles[30] = true;
BlacklistTiles[37] = true;
BlacklistTiles[38] = true;
BlacklistTiles[39] = true;
BlacklistTiles[40] = true;
BlacklistTiles[41] = true;
BlacklistTiles[43] = true;
BlacklistTiles[44] = true;
BlacklistTiles[45] = true;
BlacklistTiles[46] = true;
BlacklistTiles[47] = true;
BlacklistTiles[53] = true;
BlacklistTiles[54] = true;
BlacklistTiles[56] = true;
BlacklistTiles[57] = true;
BlacklistTiles[58] = true;
BlacklistTiles[59] = true;
BlacklistTiles[60] = true;
BlacklistTiles[63] = true;
BlacklistTiles[64] = true;
BlacklistTiles[65] = true;
BlacklistTiles[66] = true;
BlacklistTiles[67] = true;
BlacklistTiles[68] = true;
BlacklistTiles[70] = true;
BlacklistTiles[75] = true;
BlacklistTiles[76] = true;
#endregion Blacklisted tiles
}
public TShock(Main game) public TShock(Main game)
: base(game) : base(game)
{ {
GetDataFuncs = new Dictionary<byte, HandleGetDataD>
{
{(byte)PacketTypes.PlayerInfo, HandlePlayerInfo},
{(byte)PacketTypes.TileSendSection, HandleSendSection},
{(byte)PacketTypes.PlayerUpdate, HandlePlayerUpdate},
{(byte)PacketTypes.Tile, HandleTile},
{(byte)PacketTypes.TileSendSquare, HandleSendTileSquare},
{(byte)PacketTypes.NPCUpdate, HandleNpcUpdate},
{(byte)PacketTypes.PlayerDamage, HandlePlayerDamage},
{(byte)PacketTypes.ProjectileNew, HandleProjectileNew},
{(byte)PacketTypes.TogglePVP, HandleTogglePvp},
{(byte)PacketTypes.TileKill, HandleTileKill},
{(byte)PacketTypes.PlayerKillMe, HandlePlayerKillMe},
{(byte)PacketTypes.LiquidSet, HandleLiquidSet},
};
} }
public override void Initialize() public override void Initialize()
{ {
try FileTools.SetupConfig();
{
FileTools.SetupConfig();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
string version = string.Format("TShock Version {0} ({1}) now running.", Version, VersionCodename); string version = string.Format("TShock Version {0} ({1}) now running.", Version, VersionCodename);
Console.WriteLine(version); Console.WriteLine(version);
@ -156,13 +79,13 @@ namespace TShockAPI
GameHooks.PostInitialize += OnPostInit; GameHooks.PostInitialize += OnPostInit;
GameHooks.Update += OnUpdate; GameHooks.Update += OnUpdate;
ServerHooks.Chat += OnChat;
ServerHooks.Join += OnJoin; ServerHooks.Join += OnJoin;
ServerHooks.Leave += OnLeave; ServerHooks.Leave += OnLeave;
ServerHooks.Chat += OnChat;
ServerHooks.Command += ServerHooks_OnCommand;
NetHooks.GetData += GetData; NetHooks.GetData += GetData;
NetHooks.GreetPlayer += OnGreetPlayer; NetHooks.GreetPlayer += OnGreetPlayer;
NpcHooks.StrikeNpc += NpcHooks_OnStrikeNpc; NpcHooks.StrikeNpc += NpcHooks_OnStrikeNpc;
ServerHooks.Command += ServerHooks_OnCommand;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Log.Info("Hooks initialized"); Log.Info("Hooks initialized");
@ -170,6 +93,9 @@ namespace TShockAPI
Bans.LoadBans(); Bans.LoadBans();
Log.Info("Bans initialized"); Log.Info("Bans initialized");
GetDataHandlers.InitGetDataHandler();
Log.Info("Get data handlers initialized");
Commands.InitCommands(); Commands.InitCommands();
Log.Info("Commands initialized"); Log.Info("Commands initialized");
@ -179,12 +105,11 @@ namespace TShockAPI
public override void DeInitialize() public override void DeInitialize()
{ {
Bans.SaveBans(); Bans.SaveBans();
ConfigurationManager.WriteJsonConfiguration();
GameHooks.PostInitialize -= OnPostInit; GameHooks.PostInitialize -= OnPostInit;
GameHooks.Update -= OnUpdate; GameHooks.Update -= OnUpdate;
ServerHooks.Chat -= OnChat;
ServerHooks.Join -= OnJoin; ServerHooks.Join -= OnJoin;
ServerHooks.Leave -= OnLeave; ServerHooks.Leave -= OnLeave;
ServerHooks.Chat -= OnChat;
ServerHooks.Command -= ServerHooks_OnCommand; ServerHooks.Command -= ServerHooks_OnCommand;
NetHooks.GetData -= GetData; NetHooks.GetData -= GetData;
NetHooks.GreetPlayer -= OnGreetPlayer; NetHooks.GreetPlayer -= OnGreetPlayer;
@ -210,524 +135,78 @@ namespace TShockAPI
Log.Error(e.ExceptionObject.ToString()); Log.Error(e.ExceptionObject.ToString());
} }
private void HandleCommandLine(string[] parms)
{
for (int i = 0; i < parms.Length; i++)
{
if (parms[i].ToLower() == "-ip")
{
IPAddress ip;
if (IPAddress.TryParse(parms[++i], out ip))
{
Netplay.serverListenIP = ip;
Console.Write("Using IP: {0}", ip);
}
else
{
Console.WriteLine("Bad IP: {0}", parms[i]);
}
}
}
}
/* /*
* Hooks: * Hooks:
* *
*/ */
/// <summary> private void OnPostInit()
/// When a server command is run.
/// </summary>
/// <param name="cmd"></param>
/// <param name="e"></param>
private void ServerHooks_OnCommand(string text, HandledEventArgs e)
{ {
if (text.StartsWith("/")) if (!File.Exists(Path.Combine(SavePath, "auth.lck")))
{ {
string cmdStr = text.Remove(0, 1); var r = new Random((int)DateTime.Now.ToBinary());
var args = Commands.ParseParameters(cmdStr); ConfigurationManager.AuthToken = r.Next(100000, 10000000);
if (args.Count < 1) Console.WriteLine("TShock Notice: To become SuperAdmin, join the game and type /auth " +
return; ConfigurationManager.AuthToken);
Console.WriteLine("This token will only display ONCE. This only works ONCE. If you don't use it and the server goes down, delete auth.lck.");
FileTools.CreateFile(Path.Combine(SavePath, "auth.lck"));
}
}
string scmd = args[0]; private void OnUpdate(GameTime time)
args.RemoveAt(0); {
UpdateManager.UpdateProcedureCheck();
Command cmd = null; foreach (TSPlayer player in TShock.Players)
for (int i = 0; i < Commands.ChatCommands.Count; i++) {
if (player != null && player.Active)
{ {
if (Commands.ChatCommands[i].Name.Equals(scmd)) if (player.TileThreshold >= 20)
{ {
cmd = Commands.ChatCommands[i]; if (Tools.HandleTntUser(player, "Kill tile abuse detected."))
{
RevertKillTile(player);
player.TileThreshold = 0;
player.TilesDestroyed.Clear();
}
else if (player.TileThreshold > 0)
{
player.TileThreshold = 0;
player.TilesDestroyed.Clear();
}
}
else if (player.TileThreshold > 0)
{
player.TileThreshold = 0;
} }
} }
if (cmd == null)
{
TSPlayer.Server.SendMessage("That command does not exist, try /help", Color.Red);
}
else
{
Tools.SendLogs(string.Format("{0} executed: /{1}", TSPlayer.Server.Name, cmdStr), Color.Red);
cmd.Run(cmdStr, TSPlayer.Server, args);
}
e.Handled = true;
}
else if (text.StartsWith("exit"))
{
Tools.ForceKickAll("Server shutting down!");
}
else if (text.StartsWith("playing"))
{
int count = 0;
foreach (TSPlayer player in Players)
{
if (player != null && player.Active)
{
count++;
Console.WriteLine(string.Format("{0} ({1}) [{2}]", player.Name, player.IP, player.Group.Name));
}
}
Console.WriteLine(string.Format("{0} players connected.", count));
e.Handled = true;
}
else if (text.StartsWith("say "))
Log.Info(string.Format("Server said: {0}", text.Remove(0, 4)));
}
private void NpcHooks_OnStrikeNpc(NpcStrikeEventArgs e)
{
if (ConfigurationManager.InfiniteInvasion)
{
IncrementKills();
if (Main.invasionSize < 10)
{
Main.invasionSize = 20000000;
}
}
}
private void GetData(GetDataEventArgs e)
{
if (!Netplay.serverSock[e.Msg.whoAmI].active || Netplay.serverSock[e.Msg.whoAmI].kill)
return;
if (Main.verboseNetplay)
Debug.WriteLine("{0:X} ({2}): {3} ({1:XX})", e.Msg.whoAmI, e.MsgID, Main.player[e.Msg.whoAmI].dead ? "dead " : "alive", MsgNames[e.MsgID]);
HandleGetDataD func;
if (GetDataFuncs.TryGetValue(e.MsgID, out func))
{
using (var data = new MemoryStream(e.Msg.readBuffer, e.Index, e.Length))
{
try
{
e.Handled = func(data, e);
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
}
}
bool HandlePlayerInfo(MemoryStream data, GetDataEventArgs e)
{
var player = Players[e.Msg.whoAmI];
if (player == null)
{
Tools.ForceKick(new TSPlayer(e.Msg.whoAmI), "Player doesn't exist");
return true;
}
var ban = Bans.GetBanByName(player.Name);
if (ban != null)
{
Tools.ForceKick(player, string.Format("You are banned: {0}", ban.Reason));
return true;
}
byte hair = e.Msg.readBuffer[e.Index + 1];
if (hair > 0x10)
{
Tools.ForceKick(player, "Hair crash exploit.");
return true;
}
string name = Encoding.ASCII.GetString(e.Msg.readBuffer, e.Index + 23, (e.Length - (e.Index + 23)) + e.Index - 1);
if (name.Length > 32)
{
Tools.ForceKick(player, "Name exceeded 32 characters.");
return true;
}
if (name.Trim().Length == 0)
{
Tools.ForceKick(player, "Empty Name.");
return true;
}
if (player.ReceivedInfo)
{
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "Sent client info more than once");
}
player.ReceivedInfo = true;
return false;
}
bool HandleSendTileSquare(MemoryStream data, GetDataEventArgs e)
{
short size = data.ReadInt16();
int x = data.ReadInt32();
int y = data.ReadInt32();
int plyX = Math.Abs((int)Main.player[e.Msg.whoAmI].position.X / 16);
int plyY = Math.Abs((int)Main.player[e.Msg.whoAmI].position.Y / 16);
int tileX = Math.Abs(x);
int tileY = Math.Abs(y);
if (size > 5 || (ConfigurationManager.RangeChecks && (Math.Abs(plyX - tileX) > 32 || Math.Abs(plyY - tileY) > 32)))
{
Log.Debug(string.Format("SendTileSquare(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Size:{6})",
plyX, plyY,
tileX, tileY,
Math.Abs(plyX - tileX), Math.Abs(plyY - tileY),
size
));
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "Send Tile Square Abuse");
}
return false;
}
bool HandleTile(MemoryStream data, GetDataEventArgs e)
{
byte type = data.ReadInt8();
int x = data.ReadInt32();
int y = data.ReadInt32();
byte tiletype = data.ReadInt8();
if (type == 1 || type == 3)
{
int plyX = Math.Abs((int)Main.player[e.Msg.whoAmI].position.X / 16);
int plyY = Math.Abs((int)Main.player[e.Msg.whoAmI].position.Y / 16);
int tileX = Math.Abs(x);
int tileY = Math.Abs(y);
if (Players[e.Msg.whoAmI].TPlayer.selectedItem == 0x72) //Dirt Rod
{
return Tools.Kick(Players[e.Msg.whoAmI], "Using dirt rod");
}
if (ConfigurationManager.RangeChecks && ((Math.Abs(plyX - tileX) > 32) || (Math.Abs(plyY - tileY) > 32)))
{
Log.Debug(string.Format("TilePlaced(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Type:{6})",
plyX, plyY,
tileX, tileY,
Math.Abs(plyX - tileX), Math.Abs(plyY - tileY),
tiletype
));
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "Placing impossible to place blocks.");
}
}
if (ConfigurationManager.DisableBuild)
{
if (!Players[e.Msg.whoAmI].Group.HasPermission("editspawn"))
{
Players[e.Msg.whoAmI].SendMessage("World protected from changes.", Color.Red);
RevertPlayerChanges(e.Msg.whoAmI, x, y);
return true;
}
}
if (ConfigurationManager.SpawnProtect)
{
if (!Players[e.Msg.whoAmI].Group.HasPermission("editspawn"))
{
var flag = CheckSpawn(x, y);
if (flag)
{
Players[e.Msg.whoAmI].SendMessage("Spawn protected from changes.", Color.Red);
RevertPlayerChanges(e.Msg.whoAmI, x, y);
return true;
}
}
}
if (type == 0 && BlacklistTiles[Main.tile[x, y].type] && Main.player[e.Msg.whoAmI].active)
{
Players[e.Msg.whoAmI].TileThreshold++;
var coords = new Vector2(x, y);
if (!Players[e.Msg.whoAmI].TilesDestroyed.ContainsKey(coords))
Players[e.Msg.whoAmI].TilesDestroyed.Add(coords, Main.tile[x, y]);
}
return false;
}
private static void RevertPlayerChanges(int player, int x, int y)
{
NetMessage.SendData(20, player, -1, "", 10, (float)(x - 5), (float)(y - 5), 0f);
}
bool HandleTogglePvp(MemoryStream data, GetDataEventArgs e)
{
int id = data.ReadByte();
bool pvp = data.ReadBoolean();
Main.player[e.Msg.whoAmI].hostile = pvp;
if (id != e.Msg.whoAmI)
Main.player[e.Msg.whoAmI].hostile = true;
if (ConfigurationManager.PermaPvp)
Main.player[e.Msg.whoAmI].hostile = true;
NetMessage.SendData(30, -1, -1, "", e.Msg.whoAmI);
return true;
}
bool HandleSendSection(MemoryStream data, GetDataEventArgs e)
{
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "SendSection abuse.");
}
bool HandleNpcUpdate(MemoryStream data, GetDataEventArgs e)
{
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "Spawn NPC abuse");
}
bool HandlePlayerUpdate(MemoryStream data, GetDataEventArgs e)
{
byte plr = data.ReadInt8();
byte control = data.ReadInt8();
byte item = data.ReadInt8();
float posx = data.ReadSingle();
float posy = data.ReadSingle();
float velx = data.ReadSingle();
float vely = data.ReadSingle();
if (Main.verboseNetplay)
Debug.WriteLine("Update: {{{0},{1}}} {{{2}, {3}}}", (int)posx, (int)posy, (int)velx, (int)vely);
if (plr != e.Msg.whoAmI)
{
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "Update Player abuse");
}
return false;
}
bool HandleProjectileNew(MemoryStream data, GetDataEventArgs e)
{
short ident = data.ReadInt16();
float posx = data.ReadSingle();
float posy = data.ReadSingle();
float velx = data.ReadSingle();
float vely = data.ReadSingle();
float knockback = data.ReadSingle();
short dmg = data.ReadInt16();
byte owner = data.ReadInt8();
byte type = data.ReadInt8();
if (type == 29 || type == 28 || type == 37)
{
var plr = Main.player[e.Msg.whoAmI];
Log.Debug(string.Format("Explosive(PlyXY:{0}_{1}, Type:{2})",
(int)(plr.position.X / 16),
(int)(plr.position.Y / 16),
type
));
return Tools.HandleExplosivesUser(Players[e.Msg.whoAmI], "Throwing an explosive device.");
}
return false;
}
bool HandlePlayerKillMe(MemoryStream data, GetDataEventArgs e)
{
byte id = data.ReadInt8();
byte hitdirection = data.ReadInt8();
short dmg = data.ReadInt16();
bool pvp = data.ReadBoolean();
if (id != e.Msg.whoAmI)
{
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "Trying to execute KillMe on someone else.");
}
return false;
}
bool HandlePlayerDamage(MemoryStream data, GetDataEventArgs e)
{
byte playerid = data.ReadInt8();
byte direction = data.ReadInt8();
Int16 damage = data.ReadInt16();
byte pvp = data.ReadInt8();
return !Main.player[playerid].hostile;
}
bool HandleLiquidSet(MemoryStream data, GetDataEventArgs e)
{
int x = data.ReadInt32();
int y = data.ReadInt32();
byte liquid = data.ReadInt8();
bool lava = data.ReadBoolean();
//The liquid was picked up.
if (liquid == 0)
return false;
int plyX = Math.Abs((int)Main.player[e.Msg.whoAmI].position.X / 16);
int plyY = Math.Abs((int)Main.player[e.Msg.whoAmI].position.Y / 16);
int tileX = Math.Abs(x);
int tileY = Math.Abs(y);
bool bucket = false;
for (int i = 0; i < 44; i++)
{
if (Main.player[e.Msg.whoAmI].inventory[i].type >= 205 && Main.player[e.Msg.whoAmI].inventory[i].type <= 207)
{
bucket = true;
break;
}
}
if (lava && !Players[e.Msg.whoAmI].Group.HasPermission("canlava"))
{
Players[e.Msg.whoAmI].SendMessage("You do not have permission to use lava", Color.Red);
Tools.SendLogs(string.Format("{0} tried using lava", Main.player[e.Msg.whoAmI].name), Color.Red);
return true;
}
if (!lava && !Players[e.Msg.whoAmI].Group.HasPermission("canwater"))
{
Players[e.Msg.whoAmI].SendMessage("You do not have permission to use water", Color.Red);
Tools.SendLogs(string.Format("{0} tried using water", Main.player[e.Msg.whoAmI].name), Color.Red);
return true;
}
if (!bucket)
{
Log.Debug(string.Format("{0}(PlyXY:{1}_{2}, TileXY:{3}_{4}, Result:{5}_{6}, Amount:{7})",
lava ? "Lava" : "Water",
plyX, plyY,
tileX, tileY,
Math.Abs(plyX - tileX), Math.Abs(plyY - tileY),
liquid
));
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "Manipulating liquid without bucket."); ;
}
if (ConfigurationManager.RangeChecks && ((Math.Abs(plyX - tileX) > 32) || (Math.Abs(plyY - tileY) > 32)))
{
Log.Debug(string.Format("Liquid(PlyXY:{0}_{1}, TileXY:{2}_{3}, Result:{4}_{5}, Amount:{6})",
plyX, plyY,
tileX, tileY,
Math.Abs(plyX - tileX), Math.Abs(plyY - tileY),
liquid
));
return Tools.HandleGriefer(Players[e.Msg.whoAmI], "Placing impossible to place liquid."); ;
}
if (ConfigurationManager.SpawnProtect)
{
if (!Players[e.Msg.whoAmI].Group.HasPermission("editspawn"))
{
var flag = CheckSpawn(x, y);
if (flag)
{
Players[e.Msg.whoAmI].SendMessage("The spawn is protected!", Color.Red);
return true;
}
}
}
return false;
}
bool HandleTileKill(MemoryStream data, GetDataEventArgs e)
{
int tilex = data.ReadInt32();
int tiley = data.ReadInt32();
if (tilex < 0 || tilex >= Main.maxTilesX || tiley < 0 || tiley >= Main.maxTilesY)
return false;
if (Main.tile[tilex, tiley].type != 0x15) //Chest
{
Log.Debug(string.Format("TileKill(TileXY:{0}_{1}, Type:{2})",
tilex, tiley,
Main.tile[tilex, tiley].type
));
Tools.ForceKick(Players[e.Msg.whoAmI], string.Format("Tile Kill abuse ({0})", Main.tile[tilex, tiley].type));
return true;
}
return false;
}
private void OnGreetPlayer(int who, HandledEventArgs e)
{
if (Main.netMode != 2)
return;
TSPlayer player = Players[who];
Log.Info(string.Format("{0} ({1}) from '{2}' group joined.", player.Name, player.IP, player.Group.Name));
Tools.ShowFileToUser(player, "motd.txt");
if (HackedHealth(who))
{
Tools.HandleCheater(player, "Hacked health.");
}
if (ConfigurationManager.PermaPvp)
{
Main.player[who].hostile = true;
NetMessage.SendData(30, -1, -1, "", who);
}
if (Players[who].Group.HasPermission("causeevents") && ConfigurationManager.InfiniteInvasion)
{
StartInvasion();
}
e.Handled = true;
}
private void OnChat(messageBuffer msg, int ply, string text, HandledEventArgs e)
{
if (Main.netMode != 2)
return;
if (msg.whoAmI != ply)
{
e.Handled = Tools.HandleGriefer(Players[ply], "Faking Chat");
return;
}
var tsplr = Players[msg.whoAmI];
if (tsplr.Group.HasPermission("adminchat") && !text.StartsWith("/"))
{
Tools.Broadcast(ConfigurationManager.AdminChatPrefix + "<" + tsplr.Name + "> " + text,
(byte)ConfigurationManager.AdminChatRGB[0], (byte)ConfigurationManager.AdminChatRGB[1], (byte)ConfigurationManager.AdminChatRGB[2]);
e.Handled = true;
return;
}
if (text.StartsWith("/"))
{
text = text.Remove(0, 1);
var args = Commands.ParseParameters(text);
if (args.Count < 1)
return;
string scmd = args[0];
args.RemoveAt(0);
Command cmd = null;
for (int i = 0; i < Commands.ChatCommands.Count; i++)
{
if (Commands.ChatCommands[i].Name.Equals(scmd))
{
cmd = Commands.ChatCommands[i];
}
}
if (cmd == null)
{
tsplr.SendMessage("That command does not exist, try /help", Color.Red);
}
else
{
if (!cmd.CanRun(tsplr))
{
Tools.SendLogs(string.Format("{0} tried to execute {1}", tsplr.Name, cmd.Name), Color.Red);
tsplr.SendMessage("You do not have access to that command.", Color.Red);
}
else
{
Tools.SendLogs(string.Format("{0} executed: /{1}", tsplr.Name, text), Color.Red);
cmd.Run(text, tsplr, args);
}
}
e.Handled = true;
}
else
{
Log.Info(string.Format("{0} said: {1}", tsplr.Name, text));
} }
} }
private void OnJoin(int ply, HandledEventArgs handler) private void OnJoin(int ply, HandledEventArgs handler)
{ {
if (Main.netMode != 2) if (Main.netMode != 2 || handler.Handled)
{
return; return;
}
var player = new TSPlayer(ply); var player = new TSPlayer(ply);
player.Group = Tools.GetGroupForIP(player.IP); player.Group = Tools.GetGroupForIP(player.IP);
@ -769,65 +248,143 @@ namespace TShockAPI
Players[ply] = null; Players[ply] = null;
} }
private void OnPostInit() private void OnChat(messageBuffer msg, int ply, string text, HandledEventArgs e)
{ {
if (!File.Exists(Path.Combine(SavePath, "auth.lck"))) if (Main.netMode != 2)
return;
if (msg.whoAmI != ply)
{ {
var r = new Random((int)DateTime.Now.ToBinary()); e.Handled = Tools.HandleGriefer(Players[ply], "Faking Chat");
ConfigurationManager.AuthToken = r.Next(100000, 10000000); return;
Console.WriteLine("TShock Notice: To become SuperAdmin, join the game and type /auth " + }
ConfigurationManager.AuthToken);
Console.WriteLine("This token will only display ONCE. This only works ONCE. If you don't use it and the server goes down, delete auth.lck."); var tsplr = Players[msg.whoAmI];
FileTools.CreateFile(Path.Combine(SavePath, "auth.lck"));
if (tsplr.Group.HasPermission("adminchat") && !text.StartsWith("/"))
{
Tools.Broadcast(ConfigurationManager.AdminChatPrefix + "<" + tsplr.Name + "> " + text,
(byte)ConfigurationManager.AdminChatRGB[0], (byte)ConfigurationManager.AdminChatRGB[1], (byte)ConfigurationManager.AdminChatRGB[2]);
e.Handled = true;
return;
}
if (text.StartsWith("/"))
{
if (Commands.HandleCommand(tsplr, text))
e.Handled = true;
}
else
{
Log.Info(string.Format("{0} said: {1}", tsplr.Name, text));
} }
} }
void HandleCommandLine(string[] parms) /// <summary>
/// When a server command is run.
/// </summary>
/// <param name="cmd"></param>
/// <param name="e"></param>
private void ServerHooks_OnCommand(string text, HandledEventArgs e)
{ {
for (int i = 0; i < parms.Length; i++) // Damn you ThreadStatic and Redigit
if (Main.rand == null)
{ {
if (parms[i].ToLower() == "-ip") Main.rand = new Random();
}
if (WorldGen.genRand == null)
{
WorldGen.genRand = new Random();
}
if (text.StartsWith("exit"))
{
Tools.ForceKickAll("Server shutting down!");
}
else if (text.StartsWith("playing") || text.StartsWith("/playing"))
{
int count = 0;
foreach (TSPlayer player in Players)
{ {
IPAddress ip; if (player != null && player.Active)
if (IPAddress.TryParse(parms[++i], out ip))
{ {
Netplay.serverListenIP = ip; count++;
Console.Write("Using IP: {0}", ip); TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}]", player.Name, player.IP, player.Group.Name));
}
else
{
Console.WriteLine("Bad IP: {0}", parms[i]);
} }
} }
TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count));
e.Handled = true;
}
else if (text.StartsWith("say "))
{
Log.Info(string.Format("Server said: {0}", text.Remove(0, 4)));
}
else if (text.StartsWith("/"))
{
if (Commands.HandleCommand(TSPlayer.Server, text))
e.Handled = true;
}
}
private void GetData(GetDataEventArgs e)
{
PacketTypes type = (PacketTypes) e.MsgID;
TSPlayer player = Players[e.Msg.whoAmI];
if (!player.ConnectionAlive)
return;
if (Main.verboseNetplay)
Debug.WriteLine("{0:X} ({2}): {3} ({1:XX})", player.Index, (byte) type, player.TPlayer.dead ? "dead " : "alive", type.ToString());
using (var data = new MemoryStream(e.Msg.readBuffer, e.Index, e.Length))
{
try
{
if (GetDataHandlers.HandlerGetData(type, player, data))
e.Handled = true;
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
} }
} }
private void OnUpdate(GameTime time) private void OnGreetPlayer(int who, HandledEventArgs e)
{ {
UpdateManager.UpdateProcedureCheck(); if (Main.netMode != 2)
foreach (TSPlayer player in TShock.Players) return;
{
if (player != null && player.Active)
{
if (player.TileThreshold >= 20)
{
if (Tools.HandleTntUser(player, "Kill tile abuse detected."))
{
RevertKillTile(player);
player.TileThreshold = 0;
player.TilesDestroyed.Clear();
}
else if (player.TileThreshold > 0)
{
player.TileThreshold = 0;
player.TilesDestroyed.Clear();
}
} TSPlayer player = Players[who];
else if (player.TileThreshold > 0) Log.Info(string.Format("{0} ({1}) from '{2}' group joined.", player.Name, player.IP, player.Group.Name));
{
player.TileThreshold = 0; Tools.ShowFileToUser(player, "motd.txt");
} if (HackedHealth(who))
{
Tools.HandleCheater(player, "Hacked health.");
}
if (ConfigurationManager.PermaPvp)
{
Main.player[who].hostile = true;
NetMessage.SendData(30, -1, -1, "", who);
}
if (Players[who].Group.HasPermission("causeevents") && ConfigurationManager.InfiniteInvasion)
{
StartInvasion();
}
e.Handled = true;
}
private void NpcHooks_OnStrikeNpc(NpcStrikeEventArgs e)
{
if (ConfigurationManager.InfiniteInvasion)
{
IncrementKills();
if (Main.invasionSize < 10)
{
Main.invasionSize = 20000000;
} }
} }
} }
@ -929,9 +486,14 @@ namespace TShockAPI
} }
} }
public static void PlayerDamage(int plr, int damage) public static void PlayerDamage(TSPlayer player, int damage)
{ {
NetMessage.SendData(26, -1, -1, "", plr, ((new Random()).Next(-1, 1)), damage, (float)0); NetMessage.SendData(26, -1, -1, "", player.Index, ((new Random()).Next(-1, 1)), damage, (float)0);
}
public static void SendTileSquare(TSPlayer player, int x, int y, int size = 10)
{
NetMessage.SendData(20, player.Index, -1, "", size, (float)(x - (size / 2)), (float)(y - (size / 2)), 0f);
} }
//TODO : Notify the player if there is more than one match. (or do we want a First() kinda thing?) //TODO : Notify the player if there is more than one match. (or do we want a First() kinda thing?)

View file

@ -59,6 +59,7 @@
<Compile Include="ConfigFile.cs" /> <Compile Include="ConfigFile.cs" />
<Compile Include="ConfigurationManager.cs" /> <Compile Include="ConfigurationManager.cs" />
<Compile Include="FileTools.cs" /> <Compile Include="FileTools.cs" />
<Compile Include="GetDataHandlers.cs" />
<Compile Include="Group.cs" /> <Compile Include="Group.cs" />
<Compile Include="Log.cs" /> <Compile Include="Log.cs" />
<Compile Include="Resources.Designer.cs"> <Compile Include="Resources.Designer.cs">

View file

@ -101,6 +101,7 @@ namespace TShockAPI
Log.Info(string.Format("Broadcast: {0}", msg)); Log.Info(string.Format("Broadcast: {0}", msg));
} }
public static void Broadcast(string msg, Color color) public static void Broadcast(string msg, Color color)
{ {
Broadcast(msg, color.R, color.G, color.B); Broadcast(msg, color.R, color.G, color.B);
@ -117,7 +118,7 @@ namespace TShockAPI
TSPlayer.Server.SendMessage(log, color); TSPlayer.Server.SendMessage(log, color);
foreach (TSPlayer player in TShock.Players) foreach (TSPlayer player in TShock.Players)
{ {
if (player != null && player.Group.HasPermission("logs")) if (player != null && player.Active && player.Group.HasPermission("logs"))
player.SendMessage(log, color); player.SendMessage(log, color);
} }
} }
@ -198,7 +199,7 @@ namespace TShockAPI
{ {
foreach(TSPlayer player in TShock.Players) foreach(TSPlayer player in TShock.Players)
{ {
if (player != null && player.TPlayer.active) if (player != null && player.Active)
{ {
Tools.ForceKick(player, reason); Tools.ForceKick(player, reason);
} }
@ -212,7 +213,7 @@ namespace TShockAPI
/// <param name="reason">string reason</param> /// <param name="reason">string reason</param>
public static void ForceKick(TSPlayer player, string reason) public static void ForceKick(TSPlayer player, string reason)
{ {
if (!Netplay.serverSock[player.Index].active || Netplay.serverSock[player.Index].kill) if (!player.ConnectionAlive)
return; return;
NetMessage.SendData(0x2, player.Index, -1, reason, 0x0, 0f, 0f, 0f); NetMessage.SendData(0x2, player.Index, -1, reason, 0x0, 0f, 0f, 0f);
Log.Info(string.Format("{0} was force kicked for : {1}", player.IP, reason)); Log.Info(string.Format("{0} was force kicked for : {1}", player.IP, reason));
@ -225,7 +226,7 @@ namespace TShockAPI
/// <param name="reason">string reason</param> /// <param name="reason">string reason</param>
public static bool Kick(TSPlayer player, string reason, string adminUserName = "") public static bool Kick(TSPlayer player, string reason, string adminUserName = "")
{ {
if (!Netplay.serverSock[player.Index].active || Netplay.serverSock[player.Index].kill) if (!player.ConnectionAlive)
return true; return true;
if (!player.Group.HasPermission("immunetokick")) if (!player.Group.HasPermission("immunetokick"))
{ {
@ -248,7 +249,7 @@ namespace TShockAPI
/// <param name="reason">string reason</param> /// <param name="reason">string reason</param>
public static bool Ban(TSPlayer player, string reason, string adminUserName = "") public static bool Ban(TSPlayer player, string reason, string adminUserName = "")
{ {
if (!Netplay.serverSock[player.Index].active || Netplay.serverSock[player.Index].kill) if (!player.ConnectionAlive)
return true; return true;
if (!player.Group.HasPermission("immunetoban")) if (!player.Group.HasPermission("immunetoban"))
{ {

View file

@ -37,11 +37,30 @@ namespace TShockAPI
/// Check once every X minutes. /// Check once every X minutes.
/// </summary> /// </summary>
static readonly int CheckXMinutes = 30; static readonly int CheckXMinutes = 30;
public static void UpdateProcedureCheck()
{
if ((DateTime.Now - lastcheck).TotalMinutes >= CheckXMinutes)
{
ThreadPool.QueueUserWorkItem(CheckUpdate);
lastcheck = DateTime.Now;
}
}
public static void CheckUpdate(object o)
{
if (ServerIsOutOfDate())
{
EnableUpdateCommand();
NotifyAdministrators(globalChanges);
}
}
/// <summary> /// <summary>
/// Checks to see if the server is out of date. /// Checks to see if the server is out of date.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static bool ServerIsOutOfDate() private static bool ServerIsOutOfDate()
{ {
WebClient client = new WebClient(); WebClient client = new WebClient();
client.Headers.Add("user-agent", client.Headers.Add("user-agent",
@ -65,42 +84,33 @@ namespace TShockAPI
return false; return false;
} }
public static void EnableUpdateCommand() private static void EnableUpdateCommand()
{ {
Commands.ChatCommands.Add(new Command("updatenow", "maintenance", Commands.UpdateNow)); if (!updateCmd)
updateCmd = true; {
Commands.AddUpdateCommand();
updateCmd = true;
}
} }
public static void NotifyAdministrators(string[] changes) private static void NotifyAdministrators(string[] changes)
{ {
NotifyAdministrator(TSPlayer.Server, changes);
foreach (TSPlayer player in TShock.Players) foreach (TSPlayer player in TShock.Players)
{ {
if (player != null && player.Active && player.Group.HasPermission("maintenance")) if (player != null && player.Active && player.Group.HasPermission("maintenance"))
{ {
player.SendMessage("The server is out of date. To update, type /updatenow."); NotifyAdministrator(player, changes);
for (int j = 4; j < changes.Length; j++)
{
player.SendMessage(changes[j], Color.Red);
}
} }
} }
} }
public static void UpdateProcedureCheck() private static void NotifyAdministrator(TSPlayer player, string[] changes)
{ {
if ((DateTime.Now - lastcheck).TotalMinutes >= CheckXMinutes) player.SendMessage("The server is out of date. To update, type /updatenow.");
for (int j = 4; j < changes.Length; j++)
{ {
ThreadPool.QueueUserWorkItem(CheckUpdate); player.SendMessage(changes[j], Color.Red);
lastcheck = DateTime.Now;
}
}
public static void CheckUpdate(object o)
{
if (ServerIsOutOfDate())
{
EnableUpdateCommand();
NotifyAdministrators(globalChanges);
} }
} }
} }