TShock/TShockAPI/TShock.cs
Zack Piispanen 0d350d53fa Fix Skeletron Prime Crash Exploiting people, naughty naughty
Set secondUpdate to stop displaying, because apparently no one knows that not being logged in is breaking the rules when requirelogin:true
2013-10-11 21:02:05 -04:00

1691 lines
51 KiB
C#
Executable file

/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. 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.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using MaxMind;
using Mono.Data.Sqlite;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using Rests;
using Terraria;
using TerrariaApi.Server;
using TShockAPI.DB;
using TShockAPI.Net;
namespace TShockAPI
{
[ApiVersion(1, 14)]
public class TShock : TerrariaPlugin
{
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
public static readonly string VersionCodename = "And the great beast rose from its slumber, ready to take on the world again.";
public static string SavePath = "tshock";
private const string LogFormatDefault = "yyyy-MM-dd_HH-mm-ss";
private static string LogFormat = LogFormatDefault;
private const string LogPathDefault = "tshock";
private static string LogPath = LogPathDefault;
private static bool LogClear = false;
public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers];
public static BanManager Bans;
public static WarpManager Warps;
public static RegionManager Regions;
public static BackupManager Backups;
public static GroupManager Groups;
public static UserManager Users;
public static ItemManager Itembans;
public static RememberedPosManager RememberedPos;
public static CharacterManager CharacterDB;
public static ConfigFile Config { get; set; }
public static IDbConnection DB;
public static bool OverridePort;
public static PacketBufferer PacketBuffer;
public static GeoIPCountry Geo;
public static SecureRest RestApi;
public static RestManager RestManager;
public static Utils Utils = Utils.Instance;
/// <summary>
/// Used for implementing REST Tokens prior to the REST system starting up.
/// </summary>
public static Dictionary<string, SecureRest.TokenData> RESTStartupTokens = new Dictionary<string, SecureRest.TokenData>();
/// <summary>
/// Called after TShock is initialized. Useful for plugins that needs hooks before tshock but also depend on tshock being loaded.
/// </summary>
public static event Action Initialized;
public override Version Version
{
get { return VersionNum; }
}
public override string Name
{
get { return "TShock"; }
}
public override string Author
{
get { return "The Nyx Team"; }
}
public override string Description
{
get { return "The administration modification of the future."; }
}
public override string UpdateURL
{
get { return ""; }
}
public TShock(Main game)
: base(game)
{
Config = new ConfigFile();
Order = 0;
}
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
public override void Initialize()
{
try
{
HandleCommandLine(Environment.GetCommandLineArgs());
if (Version.Major >= 4)
getTShockAscii();
if (!Directory.Exists(SavePath))
Directory.CreateDirectory(SavePath);
ConfigFile.ConfigRead += OnConfigRead;
FileTools.SetupConfig();
Main.ServerSideCharacter = Config.ServerSideCharacter; //FYI, This cannot be disabled once flipped.
DateTime now = DateTime.Now;
string logFilename;
string logPathSetupWarning = null;
// Log path was not already set by the command line parameter?
if (LogPath == LogPathDefault)
LogPath = Config.LogPath;
try
{
logFilename = Path.Combine(LogPath, now.ToString(LogFormat)+".log");
if (!Directory.Exists(LogPath))
Directory.CreateDirectory(LogPath);
}
catch(Exception ex)
{
logPathSetupWarning = "Could not apply the given log path / log format, defaults will be used. Exception details:\n" + ex;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(logPathSetupWarning);
Console.ForegroundColor = ConsoleColor.Gray;
// Problem with the log path or format use the default
logFilename = Path.Combine(LogPathDefault, now.ToString(LogFormatDefault) + ".log");
}
#if DEBUG
Log.Initialize(logFilename, LogLevel.All, false);
#else
Log.Initialize(logFilename, LogLevel.All & ~LogLevel.Debug, LogClear);
#endif
if (logPathSetupWarning != null)
Log.Warn(logPathSetupWarning);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
catch(Exception ex)
{
// Will be handled by the server api and written to its crashlog.txt.
throw new Exception("Fatal TShock initialization exception. See inner exception for details.", ex);
}
// Further exceptions are written to TShock's log from now on.
try
{
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{
Log.ConsoleInfo(
"TShock was improperly shut down. Please use the exit command in the future to prevent this.");
File.Delete(Path.Combine(SavePath, "tshock.pid"));
}
File.WriteAllText(Path.Combine(SavePath, "tshock.pid"), Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture));
HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
if (Config.StorageType.ToLower() == "sqlite")
{
string sql = Path.Combine(SavePath, "tshock.sqlite");
DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", sql));
}
else if (Config.StorageType.ToLower() == "mysql")
{
try
{
var hostport = Config.MySqlHost.Split(':');
DB = new MySqlConnection();
DB.ConnectionString =
String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};",
hostport[0],
hostport.Length > 1 ? hostport[1] : "3306",
Config.MySqlDbName,
Config.MySqlUsername,
Config.MySqlPassword
);
}
catch (MySqlException ex)
{
Log.Error(ex.ToString());
throw new Exception("MySql not setup correctly");
}
}
else
{
throw new Exception("Invalid storage type");
}
Backups = new BackupManager(Path.Combine(SavePath, "backups"));
Backups.KeepFor = Config.BackupKeepFor;
Backups.Interval = Config.BackupInterval;
Bans = new BanManager(DB);
Warps = new WarpManager(DB);
Regions = new RegionManager(DB);
Users = new UserManager(DB);
Groups = new GroupManager(DB);
Itembans = new ItemManager(DB);
RememberedPos = new RememberedPosManager(DB);
CharacterDB = new CharacterManager(DB);
RestApi = new SecureRest(Netplay.serverListenIP, Config.RestApiPort);
RestApi.Port = Config.RestApiPort;
RestManager = new RestManager(RestApi);
RestManager.RegisterRestfulCommands();
var geoippath = Path.Combine(SavePath, "GeoIP.dat");
if (Config.EnableGeoIP && File.Exists(geoippath))
Geo = new GeoIPCountry(geoippath);
Log.ConsoleInfo(string.Format("|> Version {0} ({1}) now running.", Version, VersionCodename));
ServerApi.Hooks.GamePostInitialize.Register(this, OnPostInit);
ServerApi.Hooks.GameUpdate.Register(this, OnUpdate);
ServerApi.Hooks.GameHardmodeTileUpdate.Register(this, OnHardUpdate);
ServerApi.Hooks.GameStatueSpawn.Register(this, OnStatueSpawn);
ServerApi.Hooks.ServerConnect.Register(this, OnConnect);
ServerApi.Hooks.ServerJoin.Register(this, OnJoin);
ServerApi.Hooks.ServerLeave.Register(this, OnLeave);
ServerApi.Hooks.ServerChat.Register(this, OnChat);
ServerApi.Hooks.ServerCommand.Register(this, ServerHooks_OnCommand);
ServerApi.Hooks.NetGetData.Register(this, OnGetData);
ServerApi.Hooks.NetSendData.Register(this, NetHooks_SendData);
ServerApi.Hooks.NetGreetPlayer.Register(this, OnGreetPlayer);
ServerApi.Hooks.NpcStrike.Register(this, NpcHooks_OnStrikeNpc);
ServerApi.Hooks.NpcSetDefaultsInt.Register(this, OnNpcSetDefaults);
ServerApi.Hooks.ProjectileSetDefaults.Register(this, OnProjectileSetDefaults);
ServerApi.Hooks.WorldStartHardMode.Register(this, OnStartHardMode);
ServerApi.Hooks.WorldSave.Register(this, SaveManager.Instance.OnSaveWorld);
ServerApi.Hooks.WorldChristmasCheck.Register(this, OnXmasCheck);
ServerApi.Hooks.NetNameCollision.Register(this, NetHooks_NameCollision);
TShockAPI.Hooks.PlayerHooks.PlayerPreLogin += OnPlayerPreLogin;
TShockAPI.Hooks.PlayerHooks.PlayerPostLogin += OnPlayerLogin;
GetDataHandlers.InitGetDataHandler();
Commands.InitCommands();
//RconHandler.StartThread();
if (Config.RestApiEnabled)
RestApi.Start();
if (Config.BufferPackets)
PacketBuffer = new PacketBufferer(this);
Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled"));
Log.ConsoleInfo("Backups " + (Backups.Interval > 0 ? "Enabled" : "Disabled"));
if (Initialized != null)
Initialized();
}
catch (Exception ex)
{
Log.Error("Fatal Startup Exception");
Log.Error(ex.ToString());
Environment.Exit(1);
}
}
private static void getTShockAscii()
{
// ReSharper disable LocalizableElement
Console.Write(" ___ ___ ___ ___ ___ \n" +
" ___ / /\\ /__/\\ / /\\ / /\\ /__/| \n" +
" / /\\ / /:/_ \\ \\:\\ / /::\\ / /:/ | |:| \n" +
" / /:/ / /:/ /\\ \\__\\:\\ / /:/\\:\\ / /:/ | |:| \n" +
" / /:/ / /:/ /::\\ ___ / /::\\ / /:/ \\:\\ / /:/ ___ __| |:| \n" +
" / /::\\ /__/:/ /:/\\:\\/__/\\ /:/\\:\\/__/:/ \\__\\:\\/__/:/ / /\\/__/\\_|:|____\n" +
"/__/:/\\:\\\\ \\:\\/:/~/:/\\ \\:\\/:/__\\/\\ \\:\\ / /:/\\ \\:\\ / /:/\\ \\:\\/:::::/\n" +
"\\__\\/ \\:\\\\ \\::/ /:/ \\ \\::/ \\ \\:\\ /:/ \\ \\:\\ /:/ \\ \\::/~~~~ \n" +
" \\ \\:\\\\__\\/ /:/ \\ \\:\\ \\ \\:\\/:/ \\ \\:\\/:/ \\ \\:\\ \n" +
" \\__\\/ /__/:/ \\ \\:\\ \\ \\::/ \\ \\::/ \\ \\:\\ \n" +
" \\__\\/ \\__\\/ \\__\\/ \\__\\/ \\__\\/ \n" +
"");
Console.WriteLine("TShock for Terraria is open & free software. If you paid, you were scammed.");
// ReSharper restore LocalizableElement
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
// NOTE: order is important here
if (Geo != null)
{
Geo.Dispose();
}
SaveManager.Instance.Dispose();
ServerApi.Hooks.GamePostInitialize.Deregister(this, OnPostInit);
ServerApi.Hooks.GameUpdate.Deregister(this, OnUpdate);
ServerApi.Hooks.GameHardmodeTileUpdate.Deregister(this, OnHardUpdate);
ServerApi.Hooks.GameStatueSpawn.Deregister(this, OnStatueSpawn);
ServerApi.Hooks.ServerConnect.Deregister(this, OnConnect);
ServerApi.Hooks.ServerJoin.Deregister(this, OnJoin);
ServerApi.Hooks.ServerLeave.Deregister(this, OnLeave);
ServerApi.Hooks.ServerChat.Deregister(this, OnChat);
ServerApi.Hooks.ServerCommand.Deregister(this, ServerHooks_OnCommand);
ServerApi.Hooks.NetGetData.Deregister(this, OnGetData);
ServerApi.Hooks.NetSendData.Deregister(this, NetHooks_SendData);
ServerApi.Hooks.NetGreetPlayer.Deregister(this, OnGreetPlayer);
ServerApi.Hooks.NpcStrike.Deregister(this, NpcHooks_OnStrikeNpc);
ServerApi.Hooks.NpcSetDefaultsInt.Deregister(this, OnNpcSetDefaults);
ServerApi.Hooks.ProjectileSetDefaults.Deregister(this, OnProjectileSetDefaults);
ServerApi.Hooks.WorldStartHardMode.Deregister(this, OnStartHardMode);
ServerApi.Hooks.WorldSave.Deregister(this, SaveManager.Instance.OnSaveWorld);
ServerApi.Hooks.WorldChristmasCheck.Deregister(this, OnXmasCheck);
ServerApi.Hooks.NetNameCollision.Deregister(this, NetHooks_NameCollision);
TShockAPI.Hooks.PlayerHooks.PlayerPostLogin -= OnPlayerLogin;
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{
File.Delete(Path.Combine(SavePath, "tshock.pid"));
}
RestApi.Dispose();
Log.Dispose();
}
base.Dispose(disposing);
}
private void OnPlayerLogin(Hooks.PlayerPostLoginEventArgs args)
{
User u = Users.GetUserByName(args.Player.UserAccountName);
List<String> KnownIps = new List<string>();
if (!string.IsNullOrWhiteSpace(u.KnownIps))
{
KnownIps = JsonConvert.DeserializeObject<List<String>>(u.KnownIps);
}
bool found = KnownIps.Any(s => s.Equals(args.Player.IP));
if (!found)
{
if (KnownIps.Count == 100)
{
KnownIps.RemoveAt(0);
}
KnownIps.Add(args.Player.IP);
}
u.KnownIps = JsonConvert.SerializeObject(KnownIps, Formatting.Indented);
Users.UpdateLogin(u);
}
private void OnPlayerPreLogin(Hooks.PlayerPreLoginEventArgs args)
{
if (args.Player.IsLoggedIn)
args.Player.SaveServerCharacter();
}
private void NetHooks_NameCollision(NameCollisionEventArgs args)
{
string ip = TShock.Utils.GetRealIP(Netplay.serverSock[args.Who].tcpClient.Client.RemoteEndPoint.ToString());
foreach (TSPlayer ply in TShock.Players)
{
if (ply == null)
{
continue;
}
if (ply.Name == args.Name && ply.Index != args.Who)
{
if (ply.IP == ip)
{
if (ply.State < 2)
{
Utils.ForceKick(ply, "Name collision and this client has no world data.", true, false);
args.Handled = true;
return;
}
else
{
args.Handled = false;
return;
}
}
}
}
args.Handled = false;
return;
}
private void OnXmasCheck(ChristmasCheckEventArgs args)
{
if (args.Handled)
return;
if(Config.ForceXmas)
{
args.Xmas = true;
args.Handled = true;
}
}
/// <summary>
/// Handles exceptions that we didn't catch or that Red fucked up
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Log.Error(e.ExceptionObject.ToString());
if (e.ExceptionObject.ToString().Contains("Terraria.Netplay.ListenForClients") ||
e.ExceptionObject.ToString().Contains("Terraria.Netplay.ServerLoop"))
{
var sb = new List<string>();
for (int i = 0; i < Netplay.serverSock.Length; i++)
{
if (Netplay.serverSock[i] == null)
{
sb.Add("Sock[" + i + "]");
}
else if (Netplay.serverSock[i].tcpClient == null)
{
sb.Add("Tcp[" + i + "]");
}
}
Log.Error(string.Join(", ", sb));
}
if (e.IsTerminating)
{
if (Main.worldPathName != null && Config.SaveWorldOnCrash)
{
Main.worldPathName += ".crash";
SaveManager.Instance.SaveWorld();
}
}
}
private void HandleCommandLine(string[] parms)
{
string path;
for (int i = 0; i < parms.Length; i++)
{
switch(parms[i].ToLower())
{
case "-configpath":
path = parms[++i];
if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
SavePath = path;
Log.ConsoleInfo("Config path has been set to " + path);
}
break;
case "-worldpath":
path = parms[++i];
if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
Main.WorldPath = path;
Log.ConsoleInfo("World path has been set to " + path);
}
break;
case "-logpath":
path = parms[++i];
if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
LogPath = path;
Log.ConsoleInfo("Log path has been set to " + path);
}
break;
case "-logformat":
LogFormat = parms[++i];
break;
case "-logclear":
bool.TryParse(parms[++i], out LogClear);
break;
case "-dump":
ConfigFile.DumpDescriptions();
Permissions.DumpDescriptions();
break;
}
}
}
public static void HandleCommandLinePostConfigLoad(string[] parms)
{
for (int i = 0; i < parms.Length; i++)
{
switch(parms[i].ToLower())
{
case "-port":
int port = Convert.ToInt32(parms[++i]);
Netplay.serverPort = port;
Config.ServerPort = port;
OverridePort = true;
Log.ConsoleInfo("Port overridden by startup argument. Set to " + port);
break;
case "-rest-token":
string token = Convert.ToString(parms[++i]);
RESTStartupTokens.Add(token, new SecureRest.TokenData { Username = "null", UserGroupName = "superadmin" });
Console.WriteLine("Startup parameter overrode REST token.");
break;
case "-rest-enabled":
Config.RestApiEnabled = Convert.ToBoolean(parms[++i]);
Console.WriteLine("Startup parameter overrode REST enable.");
break;
case "-rest-port":
Config.RestApiPort = Convert.ToInt32(parms[++i]);
Console.WriteLine("Startup parameter overrode REST port.");
break;
case "-maxplayers":
case "-players":
Config.MaxSlots = Convert.ToInt32(parms[++i]);
Console.WriteLine("Startup parameter overrode maximum player slot configuration value.");
break;
}
}
}
/*
* Hooks:
*
*/
public static int AuthToken = -1;
private void OnPostInit(EventArgs args)
{
SetConsoleTitle();
if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt")))
{
var r = new Random((int) DateTime.Now.ToBinary());
AuthToken = r.Next(100000, 10000000);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("TShock Notice: To become SuperAdmin, join the game and type /auth " + AuthToken);
Console.WriteLine("This token will display until disabled by verification. (/auth-verify)");
Console.ForegroundColor = ConsoleColor.Gray;
FileTools.CreateFile(Path.Combine(SavePath, "authcode.txt"));
using (var tw = new StreamWriter(Path.Combine(SavePath, "authcode.txt")))
{
tw.WriteLine(AuthToken);
}
}
else if (File.Exists(Path.Combine(SavePath, "authcode.txt")))
{
using (var tr = new StreamReader(Path.Combine(SavePath, "authcode.txt")))
{
AuthToken = Convert.ToInt32(tr.ReadLine());
}
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(
"TShock Notice: authcode.txt is still present, and the AuthToken located in that file will be used.");
Console.WriteLine("To become superadmin, join the game and type /auth " + AuthToken);
Console.WriteLine("This token will display until disabled by verification. (/auth-verify)");
Console.ForegroundColor = ConsoleColor.Gray;
}
else
{
AuthToken = 0;
}
Regions.ReloadAllRegions();
Lighting.lightMode = 2;
FixChestStacks();
}
private void FixChestStacks()
{
if (Config.IgnoreChestStacksOnLoad)
return;
foreach (Chest chest in Main.chest)
{
if (chest != null)
{
foreach (Item item in chest.item)
{
if (item != null && item.stack > item.maxStack)
item.stack = item.maxStack;
}
}
}
}
private DateTime LastCheck = DateTime.UtcNow;
private DateTime LastSave = DateTime.UtcNow;
private void OnUpdate(EventArgs args)
{
UpdateManager.UpdateProcedureCheck();
if (Backups.IsBackupTime)
Backups.Backup();
//call these every second, not every update
if ((DateTime.UtcNow - LastCheck).TotalSeconds >= 1)
{
OnSecondUpdate();
LastCheck = DateTime.UtcNow;
}
if (TShock.Config.ServerSideCharacter && (DateTime.UtcNow - LastSave).TotalMinutes >= Config.ServerSideCharacterSave)
{
foreach (TSPlayer player in Players)
{
// prevent null point exceptions
if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan)
{
CharacterDB.InsertPlayerData(player);
}
}
LastSave = DateTime.UtcNow;
}
}
private void OnSecondUpdate()
{
if (Config.ForceTime != "normal")
{
switch (Config.ForceTime)
{
case "day":
TSPlayer.Server.SetTime(true, 27000.0);
break;
case "night":
TSPlayer.Server.SetTime(false, 16200.0);
break;
}
}
foreach (TSPlayer player in Players)
{
if (player != null && player.Active)
{
if (player.TilesDestroyed != null)
{
if (player.TileKillThreshold >= Config.TileKillThreshold)
{
player.Disable("Reached TileKill threshold.");
TSPlayer.Server.RevertTiles(player.TilesDestroyed);
player.TilesDestroyed.Clear();
}
}
if (player.TileKillThreshold > 0)
{
player.TileKillThreshold = 0;
//We don't want to revert the entire map in case of a disable.
player.TilesDestroyed.Clear();
}
if (player.TilesCreated != null)
{
if (player.TilePlaceThreshold >= Config.TilePlaceThreshold)
{
player.Disable("Reached TilePlace threshold");
TSPlayer.Server.RevertTiles(player.TilesCreated);
player.TilesCreated.Clear();
}
}
if (player.TilePlaceThreshold > 0)
{
player.TilePlaceThreshold = 0;
}
if (player.RecentFuse >0)
player.RecentFuse--;
if ((TShock.Config.ServerSideCharacter) && (player.sX > 0) && (player.sY > 0))
{
player.TPlayer.SpawnX = player.sX;
player.TPlayer.SpawnY = player.sY;
}
if (player.RPPending >0)
{
if (player.RPPending == 1)
{
var pos = RememberedPos.GetLeavePos(player.Name, player.IP);
player.Teleport(pos.X*16, pos.Y*16 );
player.RPPending = 0;
}
else
{
player.RPPending--;
}
}
if (player.TileLiquidThreshold >= Config.TileLiquidThreshold)
{
player.Disable("Reached TileLiquid threshold");
}
if (player.TileLiquidThreshold > 0)
{
player.TileLiquidThreshold = 0;
}
if (player.ProjectileThreshold >= Config.ProjectileThreshold)
{
player.Disable("Reached projectile threshold");
}
if (player.ProjectileThreshold > 0)
{
player.ProjectileThreshold = 0;
}
if (player.PaintThreshold >= Config.TilePaintThreshold)
{
player.Disable("Reached paint threshold");
}
if (player.PaintThreshold > 0)
{
player.PaintThreshold = 0;
}
if (player.Dead && (DateTime.Now - player.LastDeath).Seconds >= Config.RespawnSeconds && player.Difficulty != 2)
{
player.Spawn();
}
string check = "none";
foreach (Item item in player.TPlayer.inventory)
{
if (!player.Group.HasPermission(Permissions.ignorestackhackdetection) && item.stack > item.maxStack &&
item.type != 0)
{
check = "Remove item " + item.name + " (" + item.stack + ") exceeds max stack of " + item.maxStack;
}
}
player.IgnoreActionsForCheating = check;
check = "none";
foreach (Item item in player.TPlayer.armor)
{
if (!player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned(item.name, player))
{
player.SetBuff(30, 120); //Bleeding
player.SetBuff(36, 120); //Broken Armor
check = "Remove armor/accessory " + item.name;
}
}
player.IgnoreActionsForDisabledArmor = check;
if (CheckIgnores(player))
{
player.Disable("check ignores failed in SecondUpdate()", false);
}
else if (!player.Group.HasPermission(Permissions.usebanneditem) &&
Itembans.ItemIsBanned(player.TPlayer.inventory[player.TPlayer.selectedItem].name, player))
{
player.SetBuff(23, 120); //Cursed
}
}
}
SetConsoleTitle();
}
private void SetConsoleTitle()
{
Console.Title = string.Format("{0}{1}/{2} @ {3}:{4} (TerrariaShock v{5})",
!string.IsNullOrWhiteSpace(Config.ServerName) ? Config.ServerName + " - " : "",
Utils.ActivePlayers(),
Config.MaxSlots, Netplay.serverListenIP, Netplay.serverPort, Version);
}
private void OnHardUpdate(HardmodeTileUpdateEventArgs args)
{
if (args.Handled)
return;
if (!Config.AllowCorruptionCreep && ( args.Type == 23 || args.Type == 25 || args.Type == 0 ||
args.Type == 112 || args.Type == 23 || args.Type == 32 ) )
{
args.Handled = true;
return;
}
if (!Config.AllowHallowCreep && (args.Type == 109 || args.Type == 117 || args.Type == 116 ) )
{
args.Handled = true;
}
}
private void OnStatueSpawn( StatueSpawnEventArgs args )
{
if( args.Within200 < Config.StatueSpawn200 && args.Within600 < Config.StatueSpawn600 && args.WorldWide < Config.StatueSpawnWorld )
{
args.Handled = true;
}
else
{
args.Handled = false;
}
}
private void OnConnect(ConnectEventArgs args)
{
var player = new TSPlayer(args.Who);
if (Utils.ActivePlayers() + 1 > Config.MaxSlots + Config.ReservedSlots)
{
Utils.ForceKick(player, Config.ServerFullNoReservedReason, true, false);
args.Handled = true;
return;
}
var ipban = Bans.GetBanByIp(player.IP);
Ban ban = null;
if (ipban != null && Config.EnableIPBans)
ban = ipban;
if (ban != null)
{
if (!Utils.HasBanExpired(ban))
{
DateTime exp;
string duration = DateTime.TryParse(ban.Expiration, out exp) ? String.Format("until {0}", exp.ToString("G")) : "forever";
Utils.ForceKick(player, string.Format("You are banned {0}: {1}", duration, ban.Reason), true, false);
args.Handled = true;
return;
}
}
if (!FileTools.OnWhitelist(player.IP))
{
Utils.ForceKick(player, Config.WhitelistKickReason, true, false);
args.Handled = true;
return;
}
if (Geo != null)
{
var code = Geo.TryGetCountryCode(IPAddress.Parse(player.IP));
player.Country = code == null ? "N/A" : GeoIPCountry.GetCountryNameByCode(code);
if (code == "A1")
{
if (Config.KickProxyUsers)
{
Utils.ForceKick(player, "Proxies are not allowed.", true, false);
args.Handled = true;
return;
}
}
}
Players[args.Who] = player;
}
private void OnJoin(JoinEventArgs args)
{
var player = Players[args.Who];
if (player == null)
{
args.Handled = true;
return;
}
if (Config.KickEmptyUUID && String.IsNullOrWhiteSpace(player.UUID))
{
Utils.ForceKick(player, "Your client did not send a UUID, this server is not configured to accept such a client");
}
Ban ban = null;
if (Config.EnableBanOnUsernames)
{
var newban = Bans.GetBanByName(player.Name);
if (null != newban)
ban = newban;
}
if (Config.EnableIPBans && null == ban)
{
ban = Bans.GetBanByIp(player.IP);
}
if (Config.EnableUUIDBans && null == ban && !String.IsNullOrWhiteSpace(player.UUID))
{
ban = Bans.GetBanByUUID(player.UUID);
}
if (ban != null)
{
if (!Utils.HasBanExpired(ban))
{
DateTime exp;
string duration = DateTime.TryParse(ban.Expiration, out exp) ? String.Format("until {0}", exp.ToString("G")) : "forever";
Utils.ForceKick(player, string.Format("You are banned {0}: {1}", duration, ban.Reason), true, false);
args.Handled = true;
}
}
}
private void OnLeave(LeaveEventArgs args)
{
var tsplr = Players[args.Who];
Players[args.Who] = null;
if (tsplr != null && tsplr.ReceivedInfo)
{
if (!tsplr.SilentKickInProgress && tsplr.State >= 3)
{
Utils.Broadcast(tsplr.Name + " left", Color.Yellow);
}
Log.Info(string.Format("{0} disconnected.", tsplr.Name));
if (tsplr.IsLoggedIn && !tsplr.IgnoreActionsForClearingTrashCan && TShock.Config.ServerSideCharacter && (!tsplr.Dead || tsplr.TPlayer.difficulty != 2))
{
tsplr.PlayerData.CopyCharacter(tsplr);
CharacterDB.InsertPlayerData(tsplr);
}
if ((Config.RememberLeavePos) &&(!tsplr.LoginHarassed))
{
RememberedPos.InsertLeavePos(tsplr.Name, tsplr.IP, (int) (tsplr.X/16), (int) (tsplr.Y/16));
}
}
}
private void OnChat(ServerChatEventArgs args)
{
if (args.Handled)
return;
var tsplr = Players[args.Who];
if (tsplr == null)
{
args.Handled = true;
return;
}
/*if (!Utils.ValidString(text))
{
e.Handled = true;
return;
}*/
if (args.Text.StartsWith("/") && args.Text.Length > 1)
{
try
{
args.Handled = Commands.HandleCommand(tsplr, args.Text);
}
catch (Exception ex)
{
Log.ConsoleError("Command exception");
Log.Error(ex.ToString());
}
}
else
{
if (!tsplr.Group.HasPermission(Permissions.canchat))
{
args.Handled = true;
}
else if (tsplr.mute)
{
tsplr.SendErrorMessage("You are muted!");
args.Handled = true;
}
else if (!TShock.Config.EnableChatAboveHeads)
{
Utils.Broadcast(
String.Format(Config.ChatFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix, args.Text),
tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
args.Handled = true;
}
else
{
Player ply = Main.player[args.Who];
string name = ply.name;
ply.name = String.Format(Config.ChatAboveHeadsFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix);
NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, -1, ply.name, args.Who, 0, 0, 0, 0);
ply.name = name;
NetMessage.SendData((int) PacketTypes.ChatText, -1, args.Who, args.Text, args.Who, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, -1, name, args.Who, 0, 0, 0, 0);
string msg = String.Format("<{0}> {1}",
String.Format(Config.ChatAboveHeadsFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix),
args.Text);
tsplr.SendMessage(msg, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
TSPlayer.Server.SendMessage(msg, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
Log.Info(string.Format("Broadcast: {0}", msg));
args.Handled = true;
}
}
}
/// <summary>
/// When a server command is run.
/// </summary>
/// <param name="cmd"></param>
/// <param name="e"></param>
private void ServerHooks_OnCommand(CommandEventArgs args)
{
if (args.Handled)
return;
// Damn you ThreadStatic and Redigit
if (Main.rand == null)
{
Main.rand = new Random();
}
if (WorldGen.genRand == null)
{
WorldGen.genRand = new Random();
}
if (args.Command.StartsWith("playing") || args.Command.StartsWith("/playing"))
{
int count = 0;
foreach (TSPlayer player in Players)
{
if (player != null && player.Active)
{
count++;
TSPlayer.Server.SendInfoMessage(string.Format("{0} ({1}) [{2}] <{3}>", player.Name, player.IP,
player.Group.Name, player.UserAccountName));
}
}
TSPlayer.Server.SendInfoMessage(string.Format("{0} players connected.", count));
}
else if (args.Command == "autosave")
{
Main.autoSave = Config.AutoSave = !Config.AutoSave;
Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled"));
}
else if (args.Command.StartsWith("/"))
{
Commands.HandleCommand(TSPlayer.Server, args.Command);
}
else
{
Commands.HandleCommand(TSPlayer.Server, "/" + args.Command);
}
args.Handled = true;
}
private void OnGetData(GetDataEventArgs e)
{
if (e.Handled)
return;
PacketTypes type = e.MsgID;
Debug.WriteLine("Recv: {0:X}: {2} ({1:XX})", e.Msg.whoAmI, (byte) type, type);
var player = Players[e.Msg.whoAmI];
if (player == null)
{
e.Handled = true;
return;
}
if (!player.ConnectionAlive)
{
e.Handled = true;
return;
}
if (player.RequiresPassword && type != PacketTypes.PasswordSend)
{
e.Handled = true;
return;
}
if ((player.State < 10 || player.Dead) && (int) type > 12 && (int) type != 16 && (int) type != 42 && (int) type != 50 &&
(int) type != 38 && (int) type != 21)
{
e.Handled = true;
return;
}
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 OnGreetPlayer(GreetPlayerEventArgs args)
{
var player = Players[args.Who];
if (player == null)
{
args.Handled = true;
return;
}
player.LoginMS= DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
Utils.ShowFileToUser(player, "motd.txt");
if (Config.PvPMode == "always" && !player.TPlayer.hostile)
{
player.SendMessage("PvP is forced! Enable PvP else you can't do anything!", Color.Red);
}
if (!player.IsLoggedIn)
{
if (Config.ServerSideCharacter)
{
player.SendMessage(
player.IgnoreActionsForInventory = "Server side characters is enabled! Please /register or /login to play!",
Color.Red);
player.LoginHarassed = true;
}
else if (Config.RequireLogin)
{
player.SendMessage("Please /register or /login to play!", Color.Red);
player.LoginHarassed = true;
}
}
player.LastNetPosition = new Vector2(Main.spawnTileX*16f, Main.spawnTileY*16f);
if (Config.RememberLeavePos && (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero))
{
player.RPPending=3;
player.SendMessage("You will be teleported to your last known location...", Color.Red);
}
args.Handled = true;
}
private void NpcHooks_OnStrikeNpc(NpcStrikeEventArgs e)
{
if (Config.InfiniteInvasion)
{
IncrementKills();
if (Main.invasionSize < 10)
{
Main.invasionSize = 20000000;
}
}
}
private void OnProjectileSetDefaults(SetDefaultsEventArgs<Projectile, int> e)
{
//tombstone fix.
if (e.Info == 43 || (e.Info >= 201 && e.Info <= 205))
if (Config.DisableTombstones)
e.Object.SetDefaults(0);
if (e.Info == 75)
if (Config.DisableClownBombs)
e.Object.SetDefaults(0);
if (e.Info == 109)
if (Config.DisableSnowBalls)
e.Object.SetDefaults(0);
}
private void OnNpcSetDefaults(SetDefaultsEventArgs<NPC, int> e)
{
if (Itembans.ItemIsBanned(e.Object.name, null))
{
e.Object.SetDefaults(0);
}
}
/// <summary>
/// Send bytes to client using packetbuffering if available
/// </summary>
/// <param name="client">socket to send to</param>
/// <param name="bytes">bytes to send</param>
/// <returns>False on exception</returns>
public static bool SendBytes(ServerSock client, byte[] bytes)
{
if (PacketBuffer != null)
{
PacketBuffer.BufferBytes(client, bytes);
return true;
}
return SendBytesBufferless(client, bytes);
}
/// <summary>
/// Send bytes to a client ignoring the packet buffer
/// </summary>
/// <param name="client">socket to send to</param>
/// <param name="bytes">bytes to send</param>
/// <returns>False on exception</returns>
public static bool SendBytesBufferless(ServerSock client, byte[] bytes)
{
try
{
if (client.tcpClient.Connected)
client.networkStream.Write(bytes, 0, bytes.Length);
return true;
}
catch (Exception ex)
{
Log.Warn("This is a normal exception");
Log.Warn(ex.ToString());
}
return false;
}
private void NetHooks_SendData(SendDataEventArgs e)
{
if (e.MsgId == PacketTypes.Disconnect)
{
Action<ServerSock, string> senddisconnect = (sock, str) =>
{
if (sock == null || !sock.active)
return;
sock.kill = true;
using (var ms = new MemoryStream())
{
new DisconnectMsg {Reason = str}.PackFull(ms);
SendBytesBufferless(sock, ms.ToArray());
}
};
if (e.remoteClient != -1)
{
senddisconnect(Netplay.serverSock[e.remoteClient], e.text);
}
else
{
for (int i = 0; i < Netplay.serverSock.Length; i++)
{
if (e.ignoreClient != -1 && e.ignoreClient == i)
continue;
senddisconnect(Netplay.serverSock[i], e.text);
}
}
e.Handled = true;
}
if (e.MsgId == PacketTypes.WorldInfo)
{
if (e.remoteClient == -1) return;
var player = Players[e.remoteClient];
if (player == null) return;
if (Config.UseServerName)
{
using (var ms = new MemoryStream())
{
var msg = new WorldInfoMsg
{
Time = (int) Main.time,
DayTime = Main.dayTime,
MoonPhase = (byte) Main.moonPhase,
BloodMoon = Main.bloodMoon,
MaxTilesX = Main.maxTilesX,
MaxTilesY = Main.maxTilesY,
SpawnX = Main.spawnTileX,
SpawnY = Main.spawnTileY,
WorldSurface = (int) Main.worldSurface,
RockLayer = (int) Main.rockLayer,
//Sending a fake world id causes the client to not be able to find a stored spawnx/y.
//This fixes the bed spawn point bug. With a fake world id it wont be able to find the bed spawn.
WorldID = Main.worldID,
MoonType = (byte)Main.moonType,
TreeX0 = Main.treeX[0],
TreeX1 = Main.treeX[1],
TreeX2 = Main.treeX[2],
TreeStyle0 = (byte)Main.treeStyle[0],
TreeStyle1 = (byte)Main.treeStyle[1],
TreeStyle2 = (byte)Main.treeStyle[2],
TreeStyle3 = (byte)Main.treeStyle[3],
CaveBackX0 = Main.caveBackX[0],
CaveBackX1 = Main.caveBackX[1],
CaveBackX2 = Main.caveBackX[2],
CaveBackStyle0 = (byte)Main.caveBackStyle[0],
CaveBackStyle1 = (byte)Main.caveBackStyle[1],
CaveBackStyle2 = (byte)Main.caveBackStyle[2],
CaveBackStyle3 = (byte)Main.caveBackStyle[3],
SetBG0 = (byte)WorldGen.treeBG,
SetBG1 = (byte)WorldGen.corruptBG,
SetBG2 = (byte)WorldGen.jungleBG,
SetBG3 = (byte)WorldGen.snowBG,
SetBG4 = (byte)WorldGen.hallowBG,
SetBG5 = (byte)WorldGen.crimsonBG,
SetBG6 = (byte)WorldGen.desertBG,
SetBG7 = (byte)WorldGen.oceanBG,
IceBackStyle = (byte)Main.iceBackStyle,
JungleBackStyle = (byte)Main.jungleBackStyle,
HellBackStyle = (byte)Main.hellBackStyle,
WindSpeed = Main.windSpeed,
NumberOfClouds = (byte)Main.numClouds,
BossFlags = (WorldGen.shadowOrbSmashed ? BossFlags.OrbSmashed : BossFlags.None) |
(NPC.downedBoss1 ? BossFlags.DownedBoss1 : BossFlags.None) |
(NPC.downedBoss2 ? BossFlags.DownedBoss2 : BossFlags.None) |
(NPC.downedBoss3 ? BossFlags.DownedBoss3 : BossFlags.None) |
(Main.hardMode ? BossFlags.HardMode : BossFlags.None) |
(NPC.downedClown ? BossFlags.DownedClown : BossFlags.None) |
(Main.ServerSideCharacter ? BossFlags.ServerSideCharacter : BossFlags.None),
BossFlags2 = (NPC.downedMechBoss1 ? BossFlags2.DownedMechBoss1 : BossFlags2.None) |
(NPC.downedMechBoss2 ? BossFlags2.DownedMechBoss2 : BossFlags2.None) |
(NPC.downedMechBoss3 ? BossFlags2.DownedMechBoss3 : BossFlags2.None) |
(NPC.downedMechBossAny ? BossFlags2.DownedMechBossAny : BossFlags2.None) |
(Main.cloudBGActive == 1f ? BossFlags2.CloudBg : BossFlags2.None) |
(WorldGen.crimson ? BossFlags2.Crimson : BossFlags2.None),
Rain = Main.maxRaining,
WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
};
msg.PackFull(ms);
player.SendRawData(ms.ToArray());
}
e.Handled = true;
}
}
}
private void OnStartHardMode(HandledEventArgs e)
{
if (Config.DisableHardmode)
e.Handled = true;
}
/*
* Useful stuff:
* */
public static void StartInvasion(int type)
{
Main.invasionType = type;
if (Config.InfiniteInvasion)
{
Main.invasionSize = 20000000;
}
else
{
Main.invasionSize = 100 + (Config.InvasionMultiplier*Utils.ActivePlayers());
}
Main.invasionWarn = 0;
if (new Random().Next(2) == 0)
{
Main.invasionX = 0.0;
}
else
{
Main.invasionX = Main.maxTilesX;
}
}
private static int KillCount;
public static void IncrementKills()
{
KillCount++;
Random r = new Random();
int random = r.Next(5);
if (KillCount%100 == 0)
{
switch (random)
{
case 0:
Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount), Color.Green);
break;
case 1:
Utils.Broadcast(string.Format("Fatality! {0} goblins killed!", KillCount), Color.Green);
break;
case 2:
Utils.Broadcast(string.Format("Number of 'noobs' killed to date: {0}", KillCount), Color.Green);
break;
case 3:
Utils.Broadcast(string.Format("Duke Nukem would be proud. {0} goblins killed.", KillCount), Color.Green);
break;
case 4:
Utils.Broadcast(string.Format("You call that a lot? {0} goblins killed!", KillCount), Color.Green);
break;
case 5:
Utils.Broadcast(string.Format("{0} copies of Call of Duty smashed.", KillCount), Color.Green);
break;
}
}
}
public static bool CheckProjectilePermission(TSPlayer player, int index, int type)
{
if (type == 43)
{
return true;
}
if (type == 17 && !player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned("Dirt Rod", player))
//Dirt Rod Projectile
{
return true;
}
if ((type == 42 || type == 65 || type == 68) && !player.Group.HasPermission(Permissions.usebanneditem) &&
Itembans.ItemIsBanned("Sandgun", player)) //Sandgun Projectiles
{
return true;
}
Projectile proj = new Projectile();
proj.SetDefaults(type);
if (!player.Group.HasPermission(Permissions.usebanneditem) && Itembans.ItemIsBanned(proj.name, player))
{
return true;
}
if (Main.projHostile[type])
{
//player.SendMessage( proj.name, Color.Yellow);
return true;
}
return false;
}
public static bool CheckRangePermission(TSPlayer player, int x, int y, int range = 32)
{
if (Config.RangeChecks && ((Math.Abs(player.TileX - x) > range) || (Math.Abs(player.TileY - y) > range)))
{
return true;
}
return false;
}
public static bool CheckTilePermission(TSPlayer player, int tileX, int tileY, byte tileType, GetDataHandlers.EditAction actionType)
{
if (!player.Group.HasPermission(Permissions.canbuild))
{
if (TShock.Config.AllowIce && actionType != GetDataHandlers.EditAction.PlaceTile)
{
foreach (Point p in player.IceTiles)
{
if (p.X == tileX && p.Y == tileY && (Main.tile[p.X, p.Y].type == 0 || Main.tile[p.X, p.Y].type == 127))
{
player.IceTiles.Remove(p);
return false;
}
}
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000)
{
player.SendMessage("You do not have permission to build!", Color.Red);
player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
if (TShock.Config.AllowIce && actionType == GetDataHandlers.EditAction.PlaceTile && tileType == 127)
{
player.IceTiles.Add(new Point(tileX, tileY));
return false;
}
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000)
{
player.SendMessage("You do not have permission to build!", Color.Red);
player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) &&
Regions.InArea(tileX, tileY))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000)
{
player.SendMessage("This region is protected from changes.", Color.Red);
player.RPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
if (Config.DisableBuild)
{
if (!player.Group.HasPermission(Permissions.editspawn))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000)
{
player.SendMessage("The world is protected from changes.", Color.Red);
player.WPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
}
if (Config.SpawnProtection)
{
if (!player.Group.HasPermission(Permissions.editspawn))
{
if (CheckSpawn(tileX, tileY))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 2000)
{
player.SendMessage("Spawn is protected from changes.", Color.Red);
player.SPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
}
}
return false;
}
public static bool CheckTilePermission(TSPlayer player, int tileX, int tileY, bool paint = false)
{
if ((!paint && !player.Group.HasPermission(Permissions.canbuild)) ||
(paint && !player.Group.HasPermission(Permissions.canpaint)))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000)
{
player.SendMessage("You do not have permission to build!", Color.Red);
player.BPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
if (!player.Group.HasPermission(Permissions.editspawn) && !Regions.CanBuild(tileX, tileY, player) &&
Regions.InArea(tileX, tileY))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000)
{
player.SendMessage("This region is protected from changes.", Color.Red);
player.RPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
if (Config.DisableBuild)
{
if (!player.Group.HasPermission(Permissions.editspawn))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000)
{
player.SendMessage("The world is protected from changes.", Color.Red);
player.WPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
}
if (Config.SpawnProtection)
{
if (!player.Group.HasPermission(Permissions.editspawn))
{
if (CheckSpawn(tileX, tileY))
{
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.SPm) > 1000)
{
player.SendMessage("Spawn is protected from changes.", Color.Red);
player.SPm = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
}
return true;
}
}
}
return false;
}
public static bool CheckSpawn(int x, int y)
{
Vector2 tile = new Vector2(x, y);
Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY);
return Distance(spawn, tile) <= Config.SpawnProtectionRadius;
}
public static float Distance(Vector2 value1, Vector2 value2)
{
float num2 = value1.X - value2.X;
float num = value1.Y - value2.Y;
float num3 = (num2*num2) + (num*num);
return (float) Math.Sqrt(num3);
}
public static bool HackedInventory(TSPlayer player)
{
bool check = false;
Item[] inventory = player.TPlayer.inventory;
Item[] armor = player.TPlayer.armor;
Item[] dye = player.TPlayer.dye;
for (int i = 0; i < NetItem.maxNetInventory; i++)
{
if (i < NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots))
{
Item item = new Item();
if (inventory[i] != null && inventory[i].netID != 0)
{
item.netDefaults(inventory[i].netID);
item.Prefix(inventory[i].prefix);
item.AffixName();
if (inventory[i].stack > item.maxStack)
{
check = true;
player.SendMessage(
String.Format("Stack cheat detected. Remove item {0} ({1}) and then rejoin", item.name, inventory[i].stack),
Color.Cyan);
}
}
}
else if(i < (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots)))
{
Item item = new Item();
var index = i - (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots));
if (armor[index] != null && armor[index].netID != 0)
{
item.netDefaults(armor[index].netID);
item.Prefix(armor[index].prefix);
item.AffixName();
if (armor[index].stack > item.maxStack)
{
check = true;
player.SendMessage(
String.Format("Stack cheat detected. Remove armor {0} ({1}) and then rejoin", item.name, armor[i - 48].stack),
Color.Cyan);
}
}
}
else if (i < (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots)))
{
Item item = new Item();
var index = i - (NetItem.maxNetInventory - NetItem.dyeSlots);
if (dye[index] != null && dye[index].netID != 0)
{
item.netDefaults(dye[index].netID);
item.Prefix(dye[index].prefix);
item.AffixName();
if (dye[index].stack > item.maxStack)
{
check = true;
player.SendMessage(
String.Format("Stack cheat detected. Remove dye {0} ({1}) and then rejoin", item.name, dye[index].stack),
Color.Cyan);
}
}
}
}
return check;
}
public static bool CheckIgnores(TSPlayer player)
{
return Config.PvPMode == "always" && !player.TPlayer.hostile || player.IgnoreActionsForInventory != "none" || player.IgnoreActionsForCheating != "none" || player.IgnoreActionsForDisabledArmor != "none" || player.IgnoreActionsForClearingTrashCan || !player.IsLoggedIn && Config.RequireLogin;;
}
public void OnConfigRead(ConfigFile file)
{
NPC.defaultMaxSpawns = file.DefaultMaximumSpawns;
NPC.defaultSpawnRate = file.DefaultSpawnRate;
Main.autoSave = file.AutoSave;
if (Backups != null)
{
Backups.KeepFor = file.BackupKeepFor;
Backups.Interval = file.BackupInterval;
}
if (!OverridePort)
{
Netplay.serverPort = file.ServerPort;
}
if (file.MaxSlots > 235)
file.MaxSlots = 235;
Main.maxNetPlayers = file.MaxSlots + 20;
Netplay.password = "";
Netplay.spamCheck = false;
RconHandler.Password = file.RconPassword;
RconHandler.ListenPort = file.RconPort;
Utils.HashAlgo = file.HashAlgorithm;
}
}
}