diff --git a/.gitmodules b/.gitmodules
index c1f89e94..fb54e5a5 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "TerrariaServerAPI"]
path = TerrariaServerAPI
url = https://github.com/Deathmax/TerrariaAPI-Server.git
+ ignore = dirty
diff --git a/Local.testsettings b/Local.testsettings
deleted file mode 100644
index 24250d4b..00000000
--- a/Local.testsettings
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- These are default test settings for a local test run.
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index f394cf6c..13d50d62 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
+# Current Status
+This project is in maintenance mode. This means that the core team of developers' time is very limited, and only extremely game breaking bugs will be fixed. Improvements, new features, and minor issues will not be resolved by direct development until this time restriction has passed. Issues created reflecting these requests will not be worked on until this notice is removed.
+
+Thanks for your continued support of TShock for Terraria.
+
# TShock [](https://travis-ci.org/NyxStudios/TShock)
TShock is a server modification for Terraria, written in C#, and based upon the [Terraria Server API](https://github.com/Deathmax/TerrariaAPI-Server). It uses JSON for configuration management, and offers several features not present in the Terraria Server normally.
diff --git a/TShock.sln b/TShock.sln
index 904e7dcd..5044784e 100644
--- a/TShock.sln
+++ b/TShock.sln
@@ -2,15 +2,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{755F5B05-0924-47E9-9563-26EB20FE3F67}"
- ProjectSection(SolutionItems) = preProject
- Local.testsettings = Local.testsettings
- Terraria.vsmdi = Terraria.vsmdi
- EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockAPI", "TShockAPI\TShockAPI.csproj", "{49606449-072B-4CF5-8088-AA49DA586694}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{F3742F51-D7BF-4754-A68A-CD944D2A21FF}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockRestTestPlugin", "TShockRestTestPlugin\TShockRestTestPlugin.csproj", "{F2FEDAFB-58DE-4611-9168-A86112C346C7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TerrariaAPI-Server", "TerrariaServerAPI\TerrariaAPI-Server.csproj", "{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}"
@@ -38,12 +32,6 @@ Global
{49606449-072B-4CF5-8088-AA49DA586694}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{49606449-072B-4CF5-8088-AA49DA586694}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{49606449-072B-4CF5-8088-AA49DA586694}.Release|x86.ActiveCfg = Release|Any CPU
- {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {F3742F51-D7BF-4754-A68A-CD944D2A21FF}.Release|x86.ActiveCfg = Release|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
diff --git a/TShockAPI/BackupManager.cs b/TShockAPI/BackupManager.cs
index bc5cec6a..1882d0bb 100644
--- a/TShockAPI/BackupManager.cs
+++ b/TShockAPI/BackupManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs
index 72e7ff34..7837af80 100755
--- a/TShockAPI/Commands.cs
+++ b/TShockAPI/Commands.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
+using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -26,6 +27,7 @@ using System.Text;
using System.Threading;
using Terraria;
using TShockAPI.DB;
+using TerrariaApi.Server;
namespace TShockAPI
{
@@ -69,6 +71,10 @@ namespace TShockAPI
/// Gets or sets the help text of this command.
///
public string HelpText { get; set; }
+ ///
+ /// Gets or sets an extended description of this command.
+ ///
+ public string[] HelpDesc { get; set; }
///
/// Gets the name of the command.
///
@@ -118,6 +124,7 @@ namespace TShockAPI
CommandDelegate = cmd;
DoLog = true;
HelpText = "No help available.";
+ HelpDesc = null;
Names = new List(names);
Permissions = new List();
}
@@ -230,6 +237,14 @@ namespace TShockAPI
{
HelpText = "Manages item bans."
});
+ add(new Command(Permissions.manageprojectile, ProjectileBan, "projban")
+ {
+ HelpText = "Manages projectile bans."
+ });
+ add(new Command(Permissions.managetile, TileBan, "tileban")
+ {
+ HelpText = "Manages tile bans."
+ });
add(new Command(Permissions.manageregion, Region, "region")
{
HelpText = "Manages regions."
@@ -332,6 +347,10 @@ namespace TShockAPI
{
HelpText = "Kills hostile NPCs or NPCs of a certain type."
});
+ add(new Command(Permissions.renamenpc, RenameNPC, "renamenpc")
+ {
+ HelpText = "Renames an NPC."
+ });
add(new Command(Permissions.invade, Invade, "invade")
{
HelpText = "Starts an NPC invasion."
@@ -354,13 +373,17 @@ namespace TShockAPI
{
HelpText = "Sets the spawn rate of NPCs."
});
- add(new Command(Permissions.invade, PumpkinInvasion, "pumpkin")
+ add(new Command(Permissions.invade, PumpkinMoon, "pumpkinmoon", "pmoon")
{
- HelpText = "Starts a Pumpkin Moon invasion at the specified wave."
+ HelpText = "Starts a Pumpkin Moon at the specified wave."
});
- add(new Command(Permissions.invade, SnowInvasion, "snowinvasion")
+ add(new Command(Permissions.invade, FrostMoon, "frostmoon", "fmoon")
{
- HelpText = "Starts a Snow Moon invasion at the specified wave."
+ HelpText = "Starts a Frost Moon at the specified wave."
+ });
+ add(new Command(Permissions.clearangler, ClearAnglerQuests, "clearangler")
+ {
+ HelpText = "Resets the list of users who have completed an angler quest that day."
});
#endregion
#region TP Commands
@@ -377,17 +400,27 @@ namespace TShockAPI
add(new Command(Permissions.tp, TP, "tp")
{
AllowServer = false,
- HelpText = "Teleports you to another player or a coordinate."
+ HelpText = "Teleports a player to another player."
+ });
+ add(new Command(Permissions.tpothers, TPHere, "tphere")
+ {
+ AllowServer = false,
+ HelpText = "Teleports a player to yourself."
+ });
+ add(new Command(Permissions.tpnpc, TPNpc, "tpnpc")
+ {
+ AllowServer = false,
+ HelpText = "Teleports you to an npc."
+ });
+ add(new Command(Permissions.tppos, TPPos, "tppos")
+ {
+ AllowServer = false,
+ HelpText = "Teleports you to tile coordinates."
});
add(new Command(Permissions.tpallow, TPAllow, "tpallow")
{
AllowServer = false,
- HelpText = "Toggles whether other people can teleport to you."
- });
- add(new Command(Permissions.tphere, TPHere, "tphere")
- {
- AllowServer = false,
- HelpText = "Teleports another player to you."
+ HelpText = "Toggles whether other people can teleport you."
});
#endregion
#region World Commands
@@ -399,14 +432,6 @@ namespace TShockAPI
{
HelpText = "Sets a blood moon."
});
- add(new Command(Permissions.snowmoon, SnowMoon, "snowmoon")
- {
- HelpText = "Sets a snow moon."
- });
- add(new Command(Permissions.pumpkinmoon, PumpkinMoon, "pumpkinmoon")
- {
- HelpText = "Sets a pumpkin moon."
- });
add(new Command(Permissions.grow, Grow, "grow")
{
AllowServer = false,
@@ -420,6 +445,10 @@ namespace TShockAPI
{
HelpText = "Sets an eclipse."
});
+ add(new Command(Permissions.halloween, ForceHalloween, "forcehalloween")
+ {
+ HelpText = "Toggles halloween mode (goodie bags, pumpkins, etc)."
+ });
add(new Command(Permissions.xmas, ForceXmas, "forcexmas")
{
HelpText = "Toggles christmas mode (present spawning, santa, etc)."
@@ -457,6 +486,10 @@ namespace TShockAPI
{
HelpText = "Sets the world time."
});
+ add(new Command(Permissions.wind, Wind, "wind")
+ {
+ HelpText = "Changes the wind speed."
+ });
add(new Command(Permissions.worldinfo, WorldInfo, "world")
{
HelpText = "Shows information about the current world."
@@ -558,10 +591,10 @@ namespace TShockAPI
string cmdName = args[0].ToLower();
args.RemoveAt(0);
- if (Hooks.PlayerHooks.OnPlayerCommand(player, cmdName, cmdText, args))
- return true;
+ IEnumerable cmds = ChatCommands.Where(c => c.HasAlias(cmdName)).ToList();
- IEnumerable cmds = ChatCommands.Where(c => c.HasAlias(cmdName));
+ if (Hooks.PlayerHooks.OnPlayerCommand(player, cmdName, cmdText, args, ref cmds))
+ return true;
if (cmds.Count() == 0)
{
@@ -572,14 +605,14 @@ namespace TShockAPI
call(new CommandArgs(cmdText, player, args));
return true;
}
- player.SendErrorMessage("Invalid command entered. Type /help for a list of valid commands.");
+ player.SendErrorMessage("Invalid command entered. Type {0}help for a list of valid commands.", TShock.Config.CommandSpecifier);
return true;
}
foreach (Command cmd in cmds)
{
if (!cmd.CanRun(player))
{
- TShock.Utils.SendLogs(string.Format("{0} tried to execute /{1}.", player.Name, cmdText), Color.PaleVioletRed, player);
+ TShock.Utils.SendLogs(string.Format("{0} tried to execute {1}{2}.", player.Name, TShock.Config.CommandSpecifier, cmdText), Color.PaleVioletRed, player);
player.SendErrorMessage("You do not have access to this command.");
}
else if (!cmd.AllowServer && !player.RealPlayer)
@@ -589,7 +622,7 @@ namespace TShockAPI
else
{
if (cmd.DoLog)
- TShock.Utils.SendLogs(string.Format("{0} executed: /{1}.", player.Name, cmdText), Color.PaleVioletRed, player);
+ TShock.Utils.SendLogs(string.Format("{0} executed: {1}{2}.", player.Name, TShock.Config.CommandSpecifier, cmdText), Color.PaleVioletRed, player);
cmd.Run(cmdText, player, args);
}
}
@@ -647,21 +680,6 @@ namespace TShockAPI
return ret;
}
- private static char GetEscape(char c)
- {
- switch (c)
- {
- case '\\':
- return '\\';
- case '"':
- return '"';
- case 't':
- return '\t';
- default:
- return c;
- }
- }
-
private static bool IsWhiteSpace(char c)
{
return c == ' ' || c == '\t' || c == '\n';
@@ -731,9 +749,9 @@ namespace TShockAPI
var group = TShock.Utils.GetGroup(user.Group);
- if (TShock.Config.ServerSideCharacter)
+ if (Main.ServerSideCharacter)
{
- if (group.HasPermission(Permissions.bypassinventorychecks))
+ if (group.HasPermission(Permissions.bypassssc))
{
args.Player.IgnoreActionsForClearingTrashCan = false;
}
@@ -754,7 +772,7 @@ namespace TShockAPI
args.Player.IsLoggedIn = true;
args.Player.IgnoreActionsForInventory = "none";
- if (!args.Player.IgnoreActionsForClearingTrashCan && TShock.Config.ServerSideCharacter)
+ if (!args.Player.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter)
{
args.Player.PlayerData.CopyCharacter(args.Player);
TShock.CharacterDB.InsertPlayerData(args.Player);
@@ -1097,16 +1115,32 @@ namespace TShockAPI
}
List players = TShock.Utils.FindPlayer(args.Parameters[1]);
+ string reason = args.Parameters.Count > 2 ? String.Join(" ", args.Parameters.Skip(2)) : "Misbehavior.";
if (players.Count == 0)
- args.Player.SendErrorMessage("Invalid player!");
+ {
+ var user = TShock.Users.GetUserByName(args.Parameters[1]);
+ if (user != null)
+ {
+ bool force = !args.Player.RealPlayer;
+ if (TShock.Groups.GetGroupByName(user.Group).HasPermission(Permissions.immunetoban) && !force)
+ args.Player.SendErrorMessage("You can't ban {0}!", user.Name);
+ else
+ {
+ var knownIps = JsonConvert.DeserializeObject>(user.KnownIps);
+ TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.UserAccountName);
+ if (String.IsNullOrWhiteSpace(args.Player.UserAccountName))
+ TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "force " : "", reason);
+ else
+ TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", args.Player.Name, force ? "force " : "", user.Name, reason);
+ }
+ }
+ else
+ args.Player.SendErrorMessage("Invalid player or account!");
+ }
else if (players.Count > 1)
TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
else
{
- string reason = args.Parameters.Count > 2
- ? String.Join(" ", args.Parameters.GetRange(2, args.Parameters.Count - 2))
- : "Misbehavior.";
-
if (!TShock.Utils.Ban(players[0], reason, !args.Player.RealPlayer, args.Player.UserAccountName))
args.Player.SendErrorMessage("You can't ban {0}!", players[0].Name);
}
@@ -1140,24 +1174,44 @@ namespace TShockAPI
return;
}
+ int time;
+ if (!TShock.Utils.TryParseTime(args.Parameters[2], out time))
+ {
+ args.Player.SendErrorMessage("Invalid time string! Proper format: _d_h_m_s, with at least one time specifier.");
+ args.Player.SendErrorMessage("For example, 1d and 10h-30m+2m are both valid time strings, but 2 is not.");
+ return;
+ }
+
+ string reason = args.Parameters.Count > 3
+ ? String.Join(" ", args.Parameters.Skip(3))
+ : "Misbehavior.";
+
List players = TShock.Utils.FindPlayer(args.Parameters[1]);
if (players.Count == 0)
- args.Player.SendErrorMessage("Invalid player!");
+ {
+ var user = TShock.Users.GetUserByName(args.Parameters[1]);
+ if (user != null)
+ {
+ bool force = !args.Player.RealPlayer;
+ if (TShock.Groups.GetGroupByName(user.Group).HasPermission(Permissions.immunetoban) && !force)
+ args.Player.SendErrorMessage("You can't ban {0}!", user.Name);
+ else
+ {
+ var knownIps = JsonConvert.DeserializeObject>(user.KnownIps);
+ TShock.Bans.AddBan(knownIps.Last(), user.Name, user.UUID, reason, false, args.Player.UserAccountName, DateTime.UtcNow.AddSeconds(time).ToString("s"));
+ if (String.IsNullOrWhiteSpace(args.Player.UserAccountName))
+ TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", user.Name, force ? "force " : "", reason);
+ else
+ TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", args.Player.Name, force ? "force " : "", user.Name, reason);
+ }
+ }
+ else
+ args.Player.SendErrorMessage("Invalid player or account!");
+ }
else if (players.Count > 1)
TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
else
{
- int time;
- if (!TShock.Utils.TryParseTime(args.Parameters[2], out time))
- {
- args.Player.SendErrorMessage("Invalid time string! Proper format: 0d0h0m0s, with at least one time specifier.");
- return;
- }
-
- string reason = args.Parameters.Count > 3
- ? String.Join(" ", args.Parameters.GetRange(3, args.Parameters.Count - 3))
- : "Misbehavior.";
-
if (args.Player.RealPlayer && players[0].Group.HasPermission(Permissions.immunetoban))
{
args.Player.SendErrorMessage("You can't ban {0}!", players[0].Name);
@@ -1168,7 +1222,6 @@ namespace TShockAPI
false, args.Player.Name, DateTime.UtcNow.AddSeconds(time).ToString("s")))
{
players[0].Disconnect(String.Format("Banned: {0}", reason));
- Log.ConsoleInfo("Banned {0} for : '{1}'", players[0].Name, reason);
string verb = args.Player.RealPlayer ? "force " : "";
if (args.Player.RealPlayer)
TSPlayer.All.SendSuccessMessage("{0} {1}banned {2} for '{3}'", args.Player.Name, verb, players[0].Name, reason);
@@ -1230,7 +1283,7 @@ namespace TShockAPI
var lines = new List
{
- "add [reason] - Bans a player.",
+ "add [reason] - Bans a player or user account if the player is not online.",
"addip [reason] - Bans an IP.",
"addtemp [reason] - Temporarily bans a player.",
"del - Unbans a player.",
@@ -1325,7 +1378,7 @@ namespace TShockAPI
private static void SaveSSC(CommandArgs args)
{
- if (TShock.Config.ServerSideCharacter)
+ if (Main.ServerSideCharacter)
{
args.Player.SendSuccessMessage("SSC has been saved.");
foreach (TSPlayer player in TShock.Players)
@@ -1340,7 +1393,7 @@ namespace TShockAPI
private static void OverrideSSC(CommandArgs args)
{
- if (!TShock.Config.ServerSideCharacter)
+ if (!Main.ServerSideCharacter)
{
args.Player.SendErrorMessage("Server Side Characters is disabled.");
return;
@@ -1385,37 +1438,19 @@ namespace TShockAPI
args.Player.SendSuccessMessage("SSC of player \"{0}\" has been overriden.", matchedPlayer.Name);
}
- private static void ForceXmas(CommandArgs args)
- {
- if(args.Parameters.Count == 0)
- {
- args.Player.SendErrorMessage("Usage: /forcexmas [true/false]");
- args.Player.SendInfoMessage(
- String.Format("The server is currently {0} force Christmas mode.",
- (TShock.Config.ForceXmas ? "in" : "not in")));
- return;
- }
+ private static void ForceHalloween(CommandArgs args)
+ {
+ TShock.Config.ForceHalloween = !TShock.Config.ForceHalloween;
+ Main.checkHalloween();
+ TSPlayer.All.SendInfoMessage("{0} {1}abled halloween mode!", args.Player.Name, (TShock.Config.ForceHalloween ? "en" : "dis"));
+ }
- if(args.Parameters[0].ToLower() == "true")
- {
- TShock.Config.ForceXmas = true;
- Main.checkXMas();
- }
- else if(args.Parameters[0].ToLower() == "false")
- {
- TShock.Config.ForceXmas = false;
- Main.checkXMas();
- }
- else
- {
- args.Player.SendErrorMessage("Usage: /forcexmas [true/false]");
- return;
- }
-
- args.Player.SendInfoMessage(
- String.Format("The server is currently {0} force Christmas mode.",
- (TShock.Config.ForceXmas ? "in" : "not in")));
- }
+ private static void ForceXmas(CommandArgs args)
+ {
+ TShock.Config.ForceXmas = !TShock.Config.ForceXmas;
+ Main.checkXMas();
+ TSPlayer.All.SendInfoMessage("{0} {1}abled Christmas mode!", args.Player.Name, (TShock.Config.ForceXmas ? "en" : "dis"));
+ }
private static void TempGroup(CommandArgs args)
{
@@ -1469,7 +1504,7 @@ namespace TShockAPI
private static void Off(CommandArgs args)
{
- if (TShock.Config.ServerSideCharacter)
+ if (Main.ServerSideCharacter)
{
foreach (TSPlayer player in TShock.Players)
{
@@ -1486,7 +1521,7 @@ namespace TShockAPI
private static void Restart(CommandArgs args)
{
- if (Main.runningMono)
+ if (ServerApi.RunningMono)
{
Log.ConsoleInfo("Sorry, this command has not yet been implemented in Mono.");
}
@@ -1506,7 +1541,15 @@ namespace TShockAPI
private static void CheckUpdates(CommandArgs args)
{
args.Player.SendInfoMessage("An update check has been queued.");
- ThreadPool.QueueUserWorkItem(UpdateManager.CheckUpdate);
+ try
+ {
+ TShock.UpdateManager.UpdateCheck(null);
+ }
+ catch (Exception)
+ {
+ //swallow the exception
+ return;
+ }
}
private static void UpdatePlugins(CommandArgs args)
@@ -1580,32 +1623,20 @@ namespace TShockAPI
private static void Fullmoon(CommandArgs args)
{
- TSPlayer.Server.SetFullMoon(true);
- TShock.Utils.Broadcast(string.Format("{0} turned on the full moon.", args.Player.Name), Color.Green);
+ TSPlayer.Server.SetFullMoon();
+ TSPlayer.All.SendInfoMessage("{0} started a full moon.", args.Player.Name);
}
private static void Bloodmoon(CommandArgs args)
{
- TSPlayer.Server.SetBloodMoon(true);
- TShock.Utils.Broadcast(string.Format("{0} turned on the blood moon.", args.Player.Name), Color.Green);
- }
-
- private static void SnowMoon(CommandArgs args)
- {
- TSPlayer.Server.SetSnowMoon(true);
- TShock.Utils.Broadcast(string.Format("{0} turned on the snow moon.", args.Player.Name), Color.Green);
- }
-
- private static void PumpkinMoon(CommandArgs args)
- {
- TSPlayer.Server.SetPumpkinMoon(true);
- TShock.Utils.Broadcast(string.Format("{0} turned on the pumpkin moon.", args.Player.Name), Color.Green);
+ TSPlayer.Server.SetBloodMoon(!Main.bloodMoon);
+ TSPlayer.All.SendInfoMessage("{0} {1}ed a blood moon.", args.Player.Name, Main.bloodMoon ? "start" : "stopp");
}
private static void Eclipse(CommandArgs args)
{
- TSPlayer.Server.SetEclipse(true);
- TShock.Utils.Broadcast(string.Format("{0} has forced an Eclipse!", args.Player.Name), Color.Green);
+ TSPlayer.Server.SetEclipse(!Main.eclipse);
+ TSPlayer.All.SendInfoMessage("{0} {1}ed an eclipse.", args.Player.Name, Main.eclipse ? "start" : "stopp");
}
private static void Invade(CommandArgs args)
@@ -1646,78 +1677,88 @@ namespace TShockAPI
}
}
- private static void PumpkinInvasion(CommandArgs args)
+ private static void PumpkinMoon(CommandArgs args)
{
- TSPlayer.Server.SetTime(false, 0.0);
-
int wave = 1;
if (args.Parameters.Count != 0)
- int.TryParse(args.Parameters[0], out wave);
+ {
+ if (!int.TryParse(args.Parameters[0], out wave) || wave <= 0)
+ {
+ args.Player.SendErrorMessage("Invalid wave!");
+ return;
+ }
+ }
- Main.pumpkinMoon = true;
+ TSPlayer.Server.SetPumpkinMoon(true);
Main.bloodMoon = false;
NPC.waveKills = 0f;
NPC.waveCount = wave;
- string text = "Pumpkin Invasion started at wave: " + wave;
- if (Main.netMode == 0)
- {
- Main.NewText(text, 175, 75, 255, false);
- return;
- }
- if (Main.netMode == 2)
- {
- NetMessage.SendData(25, -1, -1, text, 255, 175f, 75f, 255f, 0);
- }
+ TSPlayer.All.SendInfoMessage("{0} started the pumpkin moon at wave {1}!", args.Player.Name, wave);
}
- private static void SnowInvasion(CommandArgs args)
+ private static void FrostMoon(CommandArgs args)
{
- TSPlayer.Server.SetTime(false, 0.0);
-
int wave = 1;
if (args.Parameters.Count != 0)
- int.TryParse(args.Parameters[0], out wave);
-
- Main.snowMoon = true;
- Main.pumpkinMoon = false;
- Main.bloodMoon = false;
- if (Main.netMode != 1)
{
- NPC.waveKills = 0f;
- NPC.waveCount = wave;
- string text = "Snow Invasion started at wave: " + wave;
- if (Main.netMode == 0)
+ if (!int.TryParse(args.Parameters[0], out wave) || wave <= 0)
{
- Main.NewText(text, 175, 75, 255, false);
+ args.Player.SendErrorMessage("Invalid wave!");
return;
}
- if (Main.netMode == 2)
- {
- NetMessage.SendData(25, -1, -1, text, 255, 175f, 75f, 255f, 0);
- }
}
+
+ TSPlayer.Server.SetFrostMoon(true);
+ Main.bloodMoon = false;
+ NPC.waveKills = 0f;
+ NPC.waveCount = wave;
+ TSPlayer.All.SendInfoMessage("{0} started the frost moon at wave {1}!", args.Player.Name, wave);
}
- private static void Hardmode(CommandArgs args)
- {
- if (Main.hardMode)
+ private static void ClearAnglerQuests(CommandArgs args)
+ {
+ if (args.Parameters.Count > 0)
{
- Main.hardMode = false;
- args.Player.SendSuccessMessage("Hardmode is now off.");
+ var result = Main.anglerWhoFinishedToday.RemoveAll(s => s.ToLower().Equals(args.Parameters[0].ToLower()));
+ if (result > 0)
+ {
+ args.Player.SendSuccessMessage("Removed {0} players from the angler quest completion list for today.", result);
+ foreach (TSPlayer ply in TShock.Players.Where(p => p!= null && p.Active && p.TPlayer.name.ToLower().Equals(args.Parameters[0].ToLower())))
+ {
+ //this will always tell the client that they have not done the quest today.
+ ply.SendData((PacketTypes)74, "");
+ }
+ }
+ else
+ args.Player.SendErrorMessage("Failed to find any users by that name on the list.");
+
}
else
{
- if (!TShock.Config.DisableHardmode)
- {
- WorldGen.StartHardmode();
- args.Player.SendSuccessMessage("Hardmode is now on.");
- }
- else
- {
- args.Player.SendErrorMessage("Hardmode is disabled via config.");
- }
+ Main.anglerWhoFinishedToday.Clear();
+ NetMessage.SendAnglerQuest();
+ args.Player.SendSuccessMessage("Cleared all users from the angler quest completion list for today.");
}
- }
+ }
+
+ private static void Hardmode(CommandArgs args)
+ {
+ if (Main.hardMode)
+ {
+ Main.hardMode = false;
+ TSPlayer.All.SendData(PacketTypes.WorldInfo);
+ args.Player.SendSuccessMessage("Hardmode is now off.");
+ }
+ else if (!TShock.Config.DisableHardmode)
+ {
+ WorldGen.StartHardmode();
+ args.Player.SendSuccessMessage("Hardmode is now on.");
+ }
+ else
+ {
+ args.Player.SendErrorMessage("Hardmode is disabled via config.");
+ }
+ }
private static void SpawnBoss(CommandArgs args)
{
@@ -1737,6 +1778,17 @@ namespace TShockAPI
NPC npc = new NPC();
switch (args.Parameters[0].ToLower())
{
+ case "*":
+ case "all":
+ int[] npcIds = { 4, 13, 35, 50, 125, 126, 127, 134, 222, 245, 262, 266, 370 };
+ TSPlayer.Server.SetTime(false, 0.0);
+ foreach (int i in npcIds)
+ {
+ npc.SetDefaults(i);
+ TSPlayer.Server.SpawnNPC(npc.type, npc.name, amount, args.Player.TileX, args.Player.TileY);
+ }
+ TSPlayer.All.SendSuccessMessage("{0} has spawned all bosses {1} time(s).", args.Player.Name, amount);
+ return;
case "brain":
case "brain of cthulhu":
npc.SetDefaults(266);
@@ -1749,6 +1801,13 @@ namespace TShockAPI
TSPlayer.Server.SpawnNPC(npc.type, npc.name, amount, args.Player.TileX, args.Player.TileY);
TSPlayer.All.SendSuccessMessage("{0} has spawned the Destroyer {1} time(s).", args.Player.Name, amount);
return;
+ case "duke":
+ case "duke fishron":
+ case "fishron":
+ npc.SetDefaults(370);
+ TSPlayer.Server.SpawnNPC(npc.type, npc.name, amount, args.Player.TileX, args.Player.TileY);
+ TSPlayer.All.SendSuccessMessage("{0} has spawned Duke Fishron {1} time(s).", args.Player.Name, amount);
+ return;
case "eater":
case "eater of worlds":
npc.SetDefaults(13);
@@ -1776,7 +1835,6 @@ namespace TShockAPI
return;
case "plantera":
npc.SetDefaults(262);
- TSPlayer.Server.SetTime(false, 0.0);
TSPlayer.Server.SpawnNPC(npc.type, npc.name, amount, args.Player.TileX, args.Player.TileY);
TSPlayer.All.SendSuccessMessage("{0} has spawned Plantera {1} time(s).", args.Player.Name, amount);
return;
@@ -1903,100 +1961,237 @@ namespace TShockAPI
private static void TP(CommandArgs args)
{
- if (args.Parameters.Count < 1)
+ if (args.Parameters.Count != 1 && args.Parameters.Count != 2)
{
- args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tp ");
- args.Player.SendErrorMessage(" /tp ");
+ if (args.Player.Group.HasPermission(Permissions.tpothers))
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tp [player 2]");
+ else
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tp ");
return;
}
- if(args.Parameters.Count == 2)
+ if (args.Parameters.Count == 1)
{
- float x, y;
- if (float.TryParse(args.Parameters[0], out x) && float.TryParse(args.Parameters[1], out y))
+ var players = TShock.Utils.FindPlayer(args.Parameters[0]);
+ if (players.Count == 0)
+ args.Player.SendErrorMessage("Invalid player!");
+ else if (players.Count > 1)
+ TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
+ else
{
- args.Player.Teleport(x, y);
- args.Player.SendSuccessMessage("Teleported!");
+ var target = players[0];
+ if (!target.TPAllow && !args.Player.Group.HasPermission(Permissions.tpoverride))
+ {
+ args.Player.SendErrorMessage("{0} has disabled players from teleporting.", target.Name);
+ return;
+ }
+ if (args.Player.Teleport(target.TPlayer.position.X, target.TPlayer.position.Y))
+ {
+ args.Player.SendSuccessMessage("Teleported to {0}.", target.Name);
+ if (!args.Player.Group.HasPermission(Permissions.tpsilent))
+ target.SendInfoMessage("{0} teleported to you.", args.Player.Name);
+ }
}
}
else
{
- string plStr = String.Join(" ", args.Parameters);
- var players = TShock.Utils.FindPlayer(plStr);
- if (players.Count == 0)
+ if (!args.Player.Group.HasPermission(Permissions.tpothers))
{
- args.Player.SendErrorMessage("Invalid user name.");
- args.Player.SendErrorMessage("Proper syntax: /tp ");
- args.Player.SendErrorMessage(" /tp ");
+ args.Player.SendErrorMessage("You do not have access to this command.");
+ return;
}
- else if (players.Count > 1)
- TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
- else if (!players[0].TPAllow && !args.Player.Group.HasPermission(Permissions.tpall))
+ var players1 = TShock.Utils.FindPlayer(args.Parameters[0]);
+ var players2 = TShock.Utils.FindPlayer(args.Parameters[1]);
+
+ if (players2.Count == 0)
+ args.Player.SendErrorMessage("Invalid player!");
+ else if (players2.Count > 1)
+ TShock.Utils.SendMultipleMatchError(args.Player, players2.Select(p => p.Name));
+ else if (players1.Count == 0)
{
- var plr = players[0];
- args.Player.SendErrorMessage(plr.Name + " has prevented users from teleporting to them.");
- plr.SendInfoMessage(args.Player.Name + " attempted to teleport to you.");
+ if (args.Parameters[0] == "*")
+ {
+ if (!args.Player.Group.HasPermission(Permissions.tpallothers))
+ {
+ args.Player.SendErrorMessage("You do not have access to this command.");
+ return;
+ }
+
+ var target = players2[0];
+ foreach (var source in TShock.Players.Where(p => p != null && p != args.Player))
+ {
+ if (!target.TPAllow && !args.Player.Group.HasPermission(Permissions.tpoverride))
+ continue;
+ if (source.Teleport(target.TPlayer.position.X, target.TPlayer.position.Y))
+ {
+ if (args.Player != source)
+ {
+ if (args.Player.Group.HasPermission(Permissions.tpsilent))
+ source.SendSuccessMessage("You were teleported to {0}.", target.Name);
+ else
+ source.SendSuccessMessage("{0} teleported you to {1}.", args.Player.Name, target.Name);
+ }
+ if (args.Player != target)
+ {
+ if (args.Player.Group.HasPermission(Permissions.tpsilent))
+ target.SendInfoMessage("{0} was teleported to you.", source.Name);
+ if (!args.Player.Group.HasPermission(Permissions.tpsilent))
+ target.SendInfoMessage("{0} teleported {1} to you.", args.Player.Name, source.Name);
+ }
+ }
+ }
+ args.Player.SendSuccessMessage("Teleported everyone to {0}.", target.Name);
+ }
+ else
+ args.Player.SendErrorMessage("Invalid player!");
}
+ else if (players1.Count > 1)
+ TShock.Utils.SendMultipleMatchError(args.Player, players1.Select(p => p.Name));
else
{
- var plr = players[0];
- if (args.Player.Teleport(plr.TileX * 16, plr.TileY * 16 ))
+ var source = players1[0];
+ if (!source.TPAllow && !args.Player.Group.HasPermission(Permissions.tpoverride))
{
- args.Player.SendSuccessMessage(string.Format("Teleported to {0}.", plr.Name));
- if (!args.Player.Group.HasPermission(Permissions.tphide))
- plr.SendInfoMessage(args.Player.Name + " teleported to you.");
+ args.Player.SendErrorMessage("{0} has disabled players from teleporting.", source.Name);
+ return;
+ }
+ var target = players2[0];
+ if (!target.TPAllow && !args.Player.Group.HasPermission(Permissions.tpoverride))
+ {
+ args.Player.SendErrorMessage("{0} has disabled players from teleporting.", target.Name);
+ return;
+ }
+ args.Player.SendSuccessMessage("Teleported {0} to {1}.", source.Name, target.Name);
+ if (source.Teleport(target.TPlayer.position.X, target.TPlayer.position.Y))
+ {
+ if (args.Player != source)
+ {
+ if (args.Player.Group.HasPermission(Permissions.tpsilent))
+ source.SendSuccessMessage("You were teleported to {0}.", target.Name);
+ else
+ source.SendSuccessMessage("{0} teleported you to {1}.", args.Player.Name, target.Name);
+ }
+ if (args.Player != target)
+ {
+ if (args.Player.Group.HasPermission(Permissions.tpsilent))
+ target.SendInfoMessage("{0} was teleported to you.", source.Name);
+ if (!args.Player.Group.HasPermission(Permissions.tpsilent))
+ target.SendInfoMessage("{0} teleported {1} to you.", args.Player.Name, source.Name);
+ }
}
}
}
-
-
- }
+ }
private static void TPHere(CommandArgs args)
{
if (args.Parameters.Count < 1)
{
- args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tphere ");
+ if (args.Player.Group.HasPermission(Permissions.tpallothers))
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tphere ");
+ else
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tphere ");
return;
}
- string plStr = String.Join(" ", args.Parameters);
-
- if (plStr == "all" || plStr == "*")
- {
- args.Player.SendInfoMessage(string.Format("You brought all players here."));
- for (int i = 0; i < Main.maxPlayers; i++)
- {
- if (Main.player[i].active && (Main.player[i] != args.TPlayer))
- {
- if (TShock.Players[i].Teleport(args.Player.TileX*16, args.Player.TileY*16 ))
- TShock.Players[i].SendSuccessMessage(string.Format("You were teleported to {0}.", args.Player.Name) + ".");
- }
- }
- return;
- }
-
- var players = TShock.Utils.FindPlayer(plStr);
+ string playerName = String.Join(" ", args.Parameters);
+ var players = TShock.Utils.FindPlayer(playerName);
if (players.Count == 0)
{
- args.Player.SendErrorMessage("Invalid player!");
+ if (playerName == "*")
+ {
+ if (!args.Player.Group.HasPermission(Permissions.tpallothers))
+ {
+ args.Player.SendErrorMessage("You do not have permission to use this command.");
+ return;
+ }
+ for (int i = 0; i < Main.maxPlayers; i++)
+ {
+ if (Main.player[i].active && (Main.player[i] != args.TPlayer))
+ {
+ if (TShock.Players[i].Teleport(args.TPlayer.position.X, args.TPlayer.position.Y))
+ TShock.Players[i].SendSuccessMessage(String.Format("You were teleported to {0}.", args.Player.Name));
+ }
+ }
+ args.Player.SendSuccessMessage("Teleported everyone to yourself.");
+ }
+ else
+ args.Player.SendErrorMessage("Invalid player!");
}
else if (players.Count > 1)
- {
TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
- }
else
{
var plr = players[0];
- if (plr.Teleport(args.Player.TileX*16, args.Player.TileY*16 ))
+ if (plr.Teleport(args.TPlayer.position.X, args.TPlayer.position.Y))
{
plr.SendInfoMessage("You were teleported to {0}.", args.Player.Name);
- args.Player.SendSuccessMessage("You teleported {0} here.", plr.Name);
+ args.Player.SendSuccessMessage("Teleported {0} to yourself.", plr.Name);
}
}
}
+ private static void TPNpc(CommandArgs args)
+ {
+ if (args.Parameters.Count < 1)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tpnpc ");
+ return;
+ }
+
+ var npcStr = string.Join(" ", args.Parameters);
+ var matches = new List();
+ foreach (var npc in Main.npc.Where(npc => npc.active))
+ {
+ if (string.Equals(npc.name, npcStr, StringComparison.CurrentCultureIgnoreCase))
+ {
+ matches = new List { npc };
+ break;
+ }
+ if (npc.name.ToLower().StartsWith(npcStr.ToLower()))
+ matches.Add(npc);
+ }
+
+ if (matches.Count > 1)
+ {
+ TShock.Utils.SendMultipleMatchError(args.Player, matches.Select(n => n.name));
+ return;
+ }
+ if (matches.Count == 0)
+ {
+ args.Player.SendErrorMessage("Invalid NPC!");
+ return;
+ }
+
+ var target = matches[0];
+ args.Player.Teleport(target.position.X, target.position.Y);
+ args.Player.SendSuccessMessage("Teleported to the '{0}'.", target.name);
+ }
+
+ private static void TPPos(CommandArgs args)
+ {
+ if (args.Parameters.Count != 2)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tppos ");
+ return;
+ }
+
+ int x, y;
+ if (!int.TryParse(args.Parameters[0], out x) || !int.TryParse(args.Parameters[1], out y))
+ {
+ args.Player.SendErrorMessage("Invalid tile positions!");
+ return;
+ }
+ x = Math.Max(0, x);
+ y = Math.Max(0, y);
+ x = Math.Min(x, Main.maxTilesX - 1);
+ y = Math.Min(y, Main.maxTilesY - 1);
+
+ args.Player.Teleport(16 * x, 16 * y);
+ args.Player.SendSuccessMessage("Teleported to {0}, {1}!", x, y);
+ }
+
private static void TPAllow(CommandArgs args)
{
if (!args.Player.TPAllow)
@@ -2058,11 +2253,6 @@ namespace TShockAPI
else if (TShock.Warps.Add(args.Player.TileX, args.Player.TileY, warpName))
{
args.Player.SendSuccessMessage("Warp added: " + warpName);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.managewarp))
- tsplr.SendRaptorWarp(TShock.Warps.Find(warpName));
- }
}
else
{
@@ -2082,11 +2272,6 @@ namespace TShockAPI
if (TShock.Warps.Remove(warpName))
{
args.Player.SendSuccessMessage("Warp deleted: " + warpName);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.managewarp))
- tsplr.SendRaptorWarpDeletion(warpName);
- }
}
else
args.Player.SendErrorMessage("Could not find the specified warp.");
@@ -2121,7 +2306,7 @@ namespace TShockAPI
args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /warp hide [name] ");
#endregion
}
- else if (args.Parameters[0].ToLower() == "send" && args.Player.Group.HasPermission(Permissions.tphere))
+ else if (args.Parameters[0].ToLower() == "send" && args.Player.Group.HasPermission(Permissions.tpothers))
{
#region Warp send
if (args.Parameters.Count < 3)
@@ -2181,9 +2366,9 @@ namespace TShockAPI
private static void Group(CommandArgs args)
{
- string subcmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower();
+ string subCmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower();
- switch (args.Parameters[0].ToLower())
+ switch (subCmd)
{
case "add":
#region Add group
@@ -2585,16 +2770,8 @@ namespace TShockAPI
private static void ItemBan(CommandArgs args)
{
- if (args.Parameters.Count == 0)
- {
- args.Player.SendInfoMessage("Invalid syntax! Proper syntax: /itemban [arguments]");
- args.Player.SendInfoMessage("Commands: add, allow, del, disallow, list");
- args.Player.SendInfoMessage("Arguments: add - , allow
-
");
- args.Player.SendInfoMessage("Arguments: del - , disallow
-
, list [page]");
- return;
- }
-
- switch (args.Parameters[0].ToLower())
+ string subCmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower();
+ switch (subCmd)
{
case "add":
#region Add item
@@ -2651,17 +2828,17 @@ namespace TShockAPI
ItemBan ban = TShock.Itembans.GetItemBanByName(items[0].name);
if (ban == null)
{
- args.Player.SendErrorMessage(items[0].name + " is not banned.");
+ args.Player.SendErrorMessage("{0} is not banned.", items[0].name);
return;
}
if (!ban.AllowedGroups.Contains(args.Parameters[2]))
{
TShock.Itembans.AllowGroup(items[0].name, args.Parameters[2]);
- args.Player.SendSuccessMessage(String.Format("{0} has been allowed to use {1}.", args.Parameters[2], items[0].name));
+ args.Player.SendSuccessMessage("{0} has been allowed to use {1}.", args.Parameters[2], items[0].name);
}
else
{
- args.Player.SendWarningMessage(String.Format("{0} is already allowed to use {1}.", args.Parameters[2], items[0].name));
+ args.Player.SendWarningMessage("{0} is already allowed to use {1}.", args.Parameters[2], items[0].name);
}
}
}
@@ -2694,7 +2871,7 @@ namespace TShockAPI
#endregion
return;
case "disallow":
- #region Allow group to item
+ #region Disllow group from item
{
if (args.Parameters.Count != 3)
{
@@ -2722,48 +2899,409 @@ namespace TShockAPI
ItemBan ban = TShock.Itembans.GetItemBanByName(items[0].name);
if (ban == null)
{
- args.Player.SendErrorMessage(items[0].name + " is not banned.");
+ args.Player.SendErrorMessage("{0} is not banned.", items[0].name);
return;
}
if (ban.AllowedGroups.Contains(args.Parameters[2]))
{
TShock.Itembans.RemoveGroup(items[0].name, args.Parameters[2]);
- args.Player.SendSuccessMessage(String.Format("{0} has been disallowed to use {1}.", args.Parameters[2], items[0].name));
+ args.Player.SendSuccessMessage("{0} has been disallowed to use {1}.", args.Parameters[2], items[0].name);
}
else
{
- args.Player.SendWarningMessage(String.Format("{0} is already disallowed to use {1}.", args.Parameters[2], items[0].name));
+ args.Player.SendWarningMessage("{0} is already disallowed to use {1}.", args.Parameters[2], items[0].name);
}
}
}
#endregion
return;
case "help":
- args.Player.SendInfoMessage("Syntax: /itemban [arguments]");
- args.Player.SendInfoMessage("Commands: add, allow, del, disallow, list");
- args.Player.SendInfoMessage("Arguments: add - , allow
-
");
- args.Player.SendInfoMessage("Arguments: del - , disallow
-
, list [page]");
+ #region Help
+ {
+ int pageNumber;
+ if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
+ return;
+
+ var lines = new List
+ {
+ "add - - Adds an item ban.",
+ "allow
-
- Allows a group to use an item.",
+ "del - - Deletes an item ban.",
+ "disallow
-
- Disallows a group from using an item.",
+ "list [page] - Lists all item bans."
+ };
+
+ PaginationTools.SendPage(args.Player, pageNumber, lines,
+ new PaginationTools.Settings
+ {
+ HeaderFormat = "Item Ban Sub-Commands ({0}/{1}):",
+ FooterFormat = "Type /itemban help {0} for more sub-commands."
+ }
+ );
+ }
+ #endregion
return;
case "list":
#region List items
- int pageNumber;
- if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
- return;
- IEnumerable itemNames = from itemBan in TShock.Itembans.ItemBans
- select itemBan.Name;
- PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(itemNames),
- new PaginationTools.Settings
- {
- HeaderFormat = "Item bans ({0}/{1}):",
- FooterFormat = "Type /itemban list {0} for more.",
- NothingToDisplayString = "There are currently no banned items."
- });
+ {
+ int pageNumber;
+ if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
+ return;
+ IEnumerable itemNames = from itemBan in TShock.Itembans.ItemBans
+ select itemBan.Name;
+ PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(itemNames),
+ new PaginationTools.Settings
+ {
+ HeaderFormat = "Item bans ({0}/{1}):",
+ FooterFormat = "Type /itemban list {0} for more.",
+ NothingToDisplayString = "There are currently no banned items."
+ });
+ }
#endregion
return;
}
}
#endregion Item Management
+ #region Projectile Management
+
+ private static void ProjectileBan(CommandArgs args)
+ {
+ string subCmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower();
+ switch (subCmd)
+ {
+ case "add":
+ #region Add projectile
+ {
+ if (args.Parameters.Count != 2)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /projban add ");
+ return;
+ }
+ short id;
+ if (Int16.TryParse(args.Parameters[1], out id) && id > 0 && id < Main.maxProjectileTypes)
+ {
+ TShock.ProjectileBans.AddNewBan(id);
+ args.Player.SendSuccessMessage("Banned projectile {0}.", id);
+ }
+ else
+ args.Player.SendErrorMessage("Invalid projectile ID!");
+ }
+ #endregion
+ return;
+ case "allow":
+ #region Allow group to projectile
+ {
+ if (args.Parameters.Count != 3)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /projban allow ");
+ return;
+ }
+
+ short id;
+ if (Int16.TryParse(args.Parameters[1], out id) && id > 0 && id < Main.maxProjectileTypes)
+ {
+ if (!TShock.Groups.GroupExists(args.Parameters[2]))
+ {
+ args.Player.SendErrorMessage("Invalid group.");
+ return;
+ }
+
+ ProjectileBan ban = TShock.ProjectileBans.GetBanById(id);
+ if (ban == null)
+ {
+ args.Player.SendErrorMessage("Projectile {0} is not banned.", id);
+ return;
+ }
+ if (!ban.AllowedGroups.Contains(args.Parameters[2]))
+ {
+ TShock.ProjectileBans.AllowGroup(id, args.Parameters[2]);
+ args.Player.SendSuccessMessage("{0} has been allowed to use projectile {1}.", args.Parameters[2], id);
+ }
+ else
+ args.Player.SendWarningMessage("{0} is already allowed to use projectile {1}.", args.Parameters[2], id);
+ }
+ else
+ args.Player.SendErrorMessage("Invalid projectile ID!");
+ }
+ #endregion
+ return;
+ case "del":
+ #region Delete projectile
+ {
+ if (args.Parameters.Count != 2)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /projban del ");
+ return;
+ }
+
+ short id;
+ if (Int16.TryParse(args.Parameters[1], out id) && id > 0 && id < Main.maxProjectileTypes)
+ {
+ TShock.ProjectileBans.RemoveBan(id);
+ args.Player.SendSuccessMessage("Unbanned projectile {0}.", id);
+ return;
+ }
+ else
+ args.Player.SendErrorMessage("Invalid projectile ID!");
+ }
+ #endregion
+ return;
+ case "disallow":
+ #region Disallow group from projectile
+ {
+ if (args.Parameters.Count != 3)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /projban disallow ");
+ return;
+ }
+
+ short id;
+ if (Int16.TryParse(args.Parameters[1], out id) && id > 0 && id < Main.maxProjectileTypes)
+ {
+ if (!TShock.Groups.GroupExists(args.Parameters[2]))
+ {
+ args.Player.SendErrorMessage("Invalid group.");
+ return;
+ }
+
+ ProjectileBan ban = TShock.ProjectileBans.GetBanById(id);
+ if (ban == null)
+ {
+ args.Player.SendErrorMessage("Projectile {0} is not banned.", id);
+ return;
+ }
+ if (ban.AllowedGroups.Contains(args.Parameters[2]))
+ {
+ TShock.ProjectileBans.RemoveGroup(id, args.Parameters[2]);
+ args.Player.SendSuccessMessage("{0} has been disallowed from using projectile {1}.", args.Parameters[2], id);
+ return;
+ }
+ else
+ args.Player.SendWarningMessage("{0} is already prevented from using projectile {1}.", args.Parameters[2], id);
+ }
+ else
+ args.Player.SendErrorMessage("Invalid projectile ID!");
+ }
+ #endregion
+ return;
+ case "help":
+ #region Help
+ {
+ int pageNumber;
+ if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
+ return;
+
+ var lines = new List
+ {
+ "add - Adds a projectile ban.",
+ "allow - Allows a group to use a projectile.",
+ "del - Deletes an projectile ban.",
+ "disallow - Disallows a group from using a projectile.",
+ "list [page] - Lists all projectile bans."
+ };
+
+ PaginationTools.SendPage(args.Player, pageNumber, lines,
+ new PaginationTools.Settings
+ {
+ HeaderFormat = "Projectile Ban Sub-Commands ({0}/{1}):",
+ FooterFormat = "Type /projban help {0} for more sub-commands."
+ }
+ );
+ }
+ #endregion
+ return;
+ case "list":
+ #region List projectiles
+ {
+ int pageNumber;
+ if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
+ return;
+ IEnumerable projectileIds = from projectileBan in TShock.ProjectileBans.ProjectileBans
+ select projectileBan.ID;
+ PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(projectileIds),
+ new PaginationTools.Settings
+ {
+ HeaderFormat = "Projectile bans ({0}/{1}):",
+ FooterFormat = "Type /projban list {0} for more.",
+ NothingToDisplayString = "There are currently no banned projectiles."
+ });
+ }
+ #endregion
+ return;
+ }
+ }
+ #endregion Projectile Management
+
+ #region Tile Management
+ private static void TileBan(CommandArgs args)
+ {
+ string subCmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower();
+ switch (subCmd)
+ {
+ case "add":
+ #region Add tile
+ {
+ if (args.Parameters.Count != 2)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tileban add ");
+ return;
+ }
+ short id;
+ if (Int16.TryParse(args.Parameters[1], out id) && id >= 0 && id < Main.maxTileSets)
+ {
+ TShock.TileBans.AddNewBan(id);
+ args.Player.SendSuccessMessage("Banned tile {0}.", id);
+ }
+ else
+ args.Player.SendErrorMessage("Invalid tile ID!");
+ }
+ #endregion
+ return;
+ case "allow":
+ #region Allow group to place tile
+ {
+ if (args.Parameters.Count != 3)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tileban allow ");
+ return;
+ }
+
+ short id;
+ if (Int16.TryParse(args.Parameters[1], out id) && id >= 0 && id < Main.maxTileSets)
+ {
+ if (!TShock.Groups.GroupExists(args.Parameters[2]))
+ {
+ args.Player.SendErrorMessage("Invalid group.");
+ return;
+ }
+
+ TileBan ban = TShock.TileBans.GetBanById(id);
+ if (ban == null)
+ {
+ args.Player.SendErrorMessage("Tile {0} is not banned.", id);
+ return;
+ }
+ if (!ban.AllowedGroups.Contains(args.Parameters[2]))
+ {
+ TShock.TileBans.AllowGroup(id, args.Parameters[2]);
+ args.Player.SendSuccessMessage("{0} has been allowed to place tile {1}.", args.Parameters[2], id);
+ }
+ else
+ args.Player.SendWarningMessage("{0} is already allowed to place tile {1}.", args.Parameters[2], id);
+ }
+ else
+ args.Player.SendErrorMessage("Invalid tile ID!");
+ }
+ #endregion
+ return;
+ case "del":
+ #region Delete tile ban
+ {
+ if (args.Parameters.Count != 2)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tileban del ");
+ return;
+ }
+
+ short id;
+ if (Int16.TryParse(args.Parameters[1], out id) && id >= 0 && id < Main.maxTileSets)
+ {
+ TShock.TileBans.RemoveBan(id);
+ args.Player.SendSuccessMessage("Unbanned tile {0}.", id);
+ return;
+ }
+ else
+ args.Player.SendErrorMessage("Invalid tile ID!");
+ }
+ #endregion
+ return;
+ case "disallow":
+ #region Disallow group from placing tile
+ {
+ if (args.Parameters.Count != 3)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tileban disallow ");
+ return;
+ }
+
+ short id;
+ if (Int16.TryParse(args.Parameters[1], out id) && id >= 0 && id < Main.maxTileSets)
+ {
+ if (!TShock.Groups.GroupExists(args.Parameters[2]))
+ {
+ args.Player.SendErrorMessage("Invalid group.");
+ return;
+ }
+
+ TileBan ban = TShock.TileBans.GetBanById(id);
+ if (ban == null)
+ {
+ args.Player.SendErrorMessage("Tile {0} is not banned.", id);
+ return;
+ }
+ if (ban.AllowedGroups.Contains(args.Parameters[2]))
+ {
+ TShock.TileBans.RemoveGroup(id, args.Parameters[2]);
+ args.Player.SendSuccessMessage("{0} has been disallowed from placing tile {1}.", args.Parameters[2], id);
+ return;
+ }
+ else
+ args.Player.SendWarningMessage("{0} is already prevented from placing tile {1}.", args.Parameters[2], id);
+ }
+ else
+ args.Player.SendErrorMessage("Invalid tile ID!");
+ }
+ #endregion
+ return;
+ case "help":
+ #region Help
+ {
+ int pageNumber;
+ if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
+ return;
+
+ var lines = new List
+ {
+ "add - Adds a tile ban.",
+ "allow - Allows a group to place a tile.",
+ "del - Deletes a tile ban.",
+ "disallow - Disallows a group from place a tile.",
+ "list [page] - Lists all tile bans."
+ };
+
+ PaginationTools.SendPage(args.Player, pageNumber, lines,
+ new PaginationTools.Settings
+ {
+ HeaderFormat = "Tile Ban Sub-Commands ({0}/{1}):",
+ FooterFormat = "Type /tileban help {0} for more sub-commands."
+ }
+ );
+ }
+ #endregion
+ return;
+ case "list":
+ #region List tile bans
+ {
+ int pageNumber;
+ if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
+ return;
+ IEnumerable tileIds = from tileBan in TShock.TileBans.TileBans
+ select tileBan.ID;
+ PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(tileIds),
+ new PaginationTools.Settings
+ {
+ HeaderFormat = "Tile bans ({0}/{1}):",
+ FooterFormat = "Type /tileban list {0} for more.",
+ NothingToDisplayString = "There are currently no banned tiles."
+ });
+ }
+ #endregion
+ return;
+ }
+ }
+ #endregion Tile Management
+
#region Server Config Commands
private static void SetSpawn(CommandArgs args)
@@ -2817,74 +3355,54 @@ namespace TShockAPI
private static void MaxSpawns(CommandArgs args)
{
- if (args.Parameters.Count != 1)
+ if (args.Parameters.Count == 0)
{
- args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /maxspawns ");
- args.Player.SendErrorMessage("Proper syntax: /maxspawns show");
- args.Player.SendErrorMessage("Proper syntax: /maxspawns default");
+ args.Player.SendInfoMessage("Current maximum spawns: {0}", TShock.Config.DefaultMaximumSpawns);
return;
}
- if (args.Parameters[0] == "show")
+ if (String.Equals(args.Parameters[0], "default", StringComparison.CurrentCultureIgnoreCase))
{
- args.Player.SendInfoMessage("Current maximum spawns is " + TShock.Config.DefaultMaximumSpawns + ".");
- return;
- }
-
- if(args.Parameters[0]=="default"){
- TShock.Config.DefaultMaximumSpawns = 5;
- NPC.defaultMaxSpawns = 5;
- TSPlayer.All.SendInfoMessage(string.Format("{0} changed the maximum spawns to 5.", args.Player.Name));
+ TShock.Config.DefaultMaximumSpawns = NPC.defaultMaxSpawns = 5;
+ TSPlayer.All.SendInfoMessage("{0} changed the maximum spawns to 5.", args.Player.Name);
return;
}
- int amount = Convert.ToInt32(args.Parameters[0]);
- int.TryParse(args.Parameters[0], out amount);
- NPC.defaultMaxSpawns = amount;
- TShock.Config.DefaultMaximumSpawns = amount;
- TSPlayer.All.SendInfoMessage(string.Format("{0} changed the maximum spawns to {1}.", args.Player.Name, amount));
+ int maxSpawns = -1;
+ if (!int.TryParse(args.Parameters[0], out maxSpawns) || maxSpawns < 0 || maxSpawns > Main.maxNPCs)
+ {
+ args.Player.SendWarningMessage("Invalid maximum spawns! Acceptable range is {0} to {1}", 0, Main.maxNPCs);
+ return;
+ }
+
+ TShock.Config.DefaultMaximumSpawns = NPC.defaultMaxSpawns = maxSpawns;
+ TSPlayer.All.SendInfoMessage("{0} changed the maximum spawns to {1}.", args.Player.Name, maxSpawns);
}
private static void SpawnRate(CommandArgs args)
{
- if (args.Parameters.Count != 1)
+ if (args.Parameters.Count == 0)
{
- args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /spawnrate ");
- args.Player.SendErrorMessage("/spawnrate show");
- args.Player.SendErrorMessage("/spawnrate default");
+ args.Player.SendInfoMessage("Current spawn rate: {0}", TShock.Config.DefaultSpawnRate);
return;
}
- if (args.Parameters[0] == "show")
+ if (String.Equals(args.Parameters[0], "default", StringComparison.CurrentCultureIgnoreCase))
{
- args.Player.SendInfoMessage("Current spawn rate is " + TShock.Config.DefaultSpawnRate + ".");
+ TShock.Config.DefaultSpawnRate = NPC.defaultSpawnRate = 600;
+ TSPlayer.All.SendInfoMessage("{0} changed the spawn rate to 600.", args.Player.Name);
return;
}
- if (args.Parameters[0] == "default")
+ int spawnRate = -1;
+ if (!int.TryParse(args.Parameters[0], out spawnRate) || spawnRate < 0)
{
- TShock.Config.DefaultSpawnRate = 600;
- NPC.defaultSpawnRate = 600;
- TSPlayer.All.SendInfoMessage(string.Format("{0} changed the spawn rate to 600.", args.Player.Name));
+ args.Player.SendWarningMessage("Invalid spawn rate!");
return;
}
- int amount = -1;
- if (!int.TryParse(args.Parameters[0], out amount))
- {
- args.Player.SendWarningMessage(string.Format("Invalid spawnrate ({0})", args.Parameters[0]));
- return;
- }
-
- if (amount < 0)
- {
- args.Player.SendWarningMessage("Spawnrate cannot be negative!");
- return;
- }
-
- NPC.defaultSpawnRate = amount;
- TShock.Config.DefaultSpawnRate = amount;
- TSPlayer.All.SendInfoMessage(string.Format("{0} changed the spawn rate to {1}.", args.Player.Name, amount));
+ TShock.Config.DefaultSpawnRate = NPC.defaultSpawnRate = spawnRate;
+ TSPlayer.All.SendInfoMessage("{0} changed the spawn rate to {1}.", args.Player.Name, spawnRate);
}
#endregion Server Config Commands
@@ -2893,36 +3411,61 @@ namespace TShockAPI
private static void Time(CommandArgs args)
{
- if (args.Parameters.Count != 1)
+ if (args.Parameters.Count == 0)
{
- args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /time ");
+ double time = Main.time / 3600.0;
+ time += 4.5;
+ if (!Main.dayTime)
+ time += 15.0;
+ time = time % 24.0;
+ args.Player.SendInfoMessage("The current time is {0}:{1:D2}.", (int)Math.Floor(time), (int)Math.Round((time % 1.0) * 60.0));
return;
}
-
+
switch (args.Parameters[0].ToLower())
{
case "day":
- TSPlayer.Server.SetTime(true, 150.0);
- TSPlayer.All.SendInfoMessage("{0} set the time to day.", args.Player.Name);
+ TSPlayer.Server.SetTime(true, 0.0);
+ TSPlayer.All.SendInfoMessage("{0} set the time to 4:30.", args.Player.Name);
break;
case "night":
TSPlayer.Server.SetTime(false, 0.0);
- TSPlayer.All.SendInfoMessage("{0} set the time to night.", args.Player.Name);
- break;
- case "dusk":
- TSPlayer.Server.SetTime(false, 0.0);
- TSPlayer.All.SendInfoMessage("{0} set the time to dusk.", args.Player.Name);
+ TSPlayer.All.SendInfoMessage("{0} set the time to 19:30.", args.Player.Name);
break;
case "noon":
TSPlayer.Server.SetTime(true, 27000.0);
- TSPlayer.All.SendInfoMessage("{0} set the time to noon.", args.Player.Name);
+ TSPlayer.All.SendInfoMessage("{0} set the time to 12:00.", args.Player.Name);
break;
case "midnight":
TSPlayer.Server.SetTime(false, 16200.0);
- TSPlayer.All.SendInfoMessage("{0} set the time to midnight.", args.Player.Name);
+ TSPlayer.All.SendInfoMessage("{0} set the time to 0:00.", args.Player.Name);
break;
default:
- args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /time ");
+ string[] array = args.Parameters[0].Split(':');
+ if (array.Length != 2)
+ {
+ args.Player.SendErrorMessage("Invalid time string! Proper format: hh:mm, in 24-hour time.");
+ return;
+ }
+
+ int hours;
+ int minutes;
+ if (!int.TryParse(array[0], out hours) || hours < 0 || hours > 23
+ || !int.TryParse(array[1], out minutes) || minutes < 0 || minutes > 59)
+ {
+ args.Player.SendErrorMessage("Invalid time string! Proper format: hh:mm, in 24-hour time.");
+ return;
+ }
+
+ decimal time = hours + minutes / 60.0m;
+ time -= 4.50m;
+ if (time < 0.00m)
+ time += 24.00m;
+ if (time >= 15.00m)
+ TSPlayer.Server.SetTime(false, (double)((time - 15.00m) * 3600.0m));
+ else
+ TSPlayer.Server.SetTime(true, (double)(time * 3600.0m));
+ TSPlayer.All.SendInfoMessage("{0} set the time to {1}:{2:D2}.", args.Player.Name, hours, minutes);
break;
}
}
@@ -2993,6 +3536,28 @@ namespace TShockAPI
}
}
+ private static void Wind(CommandArgs args)
+ {
+ if (args.Parameters.Count != 1)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /wind ");
+ return;
+ }
+
+ float speed;
+ if (!float.TryParse(args.Parameters[0], out speed))
+ {
+ args.Player.SendErrorMessage("Invalid wind speed!");
+ return;
+ }
+
+ Main.windSpeed = speed;
+ Main.windSpeedSet = speed;
+ Main.windSpeedSpeed = 0f;
+ TSPlayer.All.SendData(PacketTypes.WorldInfo);
+ TSPlayer.All.SendInfoMessage("{0} changed the wind speed to {1}.", args.Player.Name, speed);
+ }
+
#endregion Time/PvpFun Commands
#region Region Commands
@@ -3049,12 +3614,6 @@ namespace TShockAPI
args.Player.TempPoints[0] = Point.Zero;
args.Player.TempPoints[1] = Point.Zero;
args.Player.SendMessage("Set region " + regionName, Color.Yellow);
-
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.manageregion))
- tsplr.SendRaptorRegion(TShock.Regions.GetRegionByName(regionName));
- }
}
else
{
@@ -3104,11 +3663,6 @@ namespace TShockAPI
if (TShock.Regions.DeleteRegion(regionName))
{
args.Player.SendInfoMessage("Deleted region \"{0}\".", regionName);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.manageregion))
- tsplr.SendRaptorRegionDeletion(regionName);
- }
}
else
args.Player.SendErrorMessage("Could not find the specified region!");
@@ -3460,11 +4014,6 @@ namespace TShockAPI
if (TShock.Regions.resizeRegion(args.Parameters[1], addAmount, direction))
{
args.Player.SendMessage("Region Resized Successfully!", Color.Yellow);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.manageregion))
- tsplr.SendRaptorRegion(TShock.Regions.GetRegionByName(args.Parameters[1]));
- }
TShock.Regions.Reload();
}
else
@@ -3608,7 +4157,15 @@ namespace TShockAPI
}
args.Player.SendSuccessMessage("/{0} help: ", command.Name);
- args.Player.SendInfoMessage(command.HelpText);
+ if (command.HelpDesc == null)
+ {
+ args.Player.SendInfoMessage(command.HelpText);
+ return;
+ }
+ foreach (string line in command.HelpDesc)
+ {
+ args.Player.SendInfoMessage(line);
+ }
}
}
@@ -3915,7 +4472,7 @@ namespace TShockAPI
{
var ply = players[0];
- if (ply.IsLoggedIn && TShock.Config.ServerSideCharacter)
+ if (ply.IsLoggedIn && Main.ServerSideCharacter)
{
ply.TPlayer.velocity.Y = -50;
TSPlayer.All.SendData(PacketTypes.PlayerUpdate, "", ply.Index);
@@ -4123,7 +4680,7 @@ namespace TShockAPI
if (args.Parameters.Count == 1)
{
- List npcs = TShock.Utils.GetNPCByIdOrName(args.Parameters[0]);
+ var npcs = TShock.Utils.GetNPCByIdOrName(args.Parameters[0]);
if (npcs.Count == 0)
{
args.Player.SendErrorMessage("Invalid mob type!");
@@ -4250,7 +4807,58 @@ namespace TShockAPI
args.Player.SendErrorMessage("Your inventory seems full.");
}
}
-
+
+ private static void RenameNPC(CommandArgs args)
+ {
+ if (args.Parameters.Count != 2)
+ {
+ args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /renameNPC ");
+ return;
+ }
+ int npcId = 0;
+ if (args.Parameters.Count == 2)
+ {
+ List npcs = TShock.Utils.GetNPCByIdOrName(args.Parameters[0]);
+ if (npcs.Count == 0)
+ {
+ args.Player.SendErrorMessage("Invalid mob type!");
+ return;
+ }
+ else if (npcs.Count > 1)
+ {
+ TShock.Utils.SendMultipleMatchError(args.Player, npcs.Select(n => n.name));
+ return;
+ }
+ else if (args.Parameters[1].Length >200)
+ {
+ args.Player.SendErrorMessage("New name is too large!");
+ return;
+ }
+ else
+ {
+ npcId = npcs[0].netID;
+ }
+ }
+ int done=0;
+ for (int i = 0; i < Main.npc.Length; i++)
+ {
+ if (Main.npc[i].active && ((npcId == 0 && !Main.npc[i].townNPC) || (Main.npc[i].netID == npcId && Main.npc[i].townNPC)))
+ {
+ Main.npc[i].displayName= args.Parameters[1];
+ NetMessage.SendData(56, -1, -1, args.Parameters[1], i, 0f, 0f, 0f, 0);
+ done++;
+ }
+ }
+ if (done >0 )
+ {
+ TSPlayer.All.SendInfoMessage("{0} renamed the {1}.", args.Player.Name, args.Parameters[0]);
+ }
+ else
+ {
+ args.Player.SendErrorMessage("Could not rename {0}!", args.Parameters[0]);
+ }
+ }
+
private static void Give(CommandArgs args)
{
if (args.Parameters.Count < 2)
@@ -4416,7 +5024,7 @@ namespace TShockAPI
}
if (args.Parameters.Count == 2)
int.TryParse(args.Parameters[1], out time);
- if (id > 0 && id < Main.maxBuffs)
+ if (id > 0 && id < Main.maxBuffTypes)
{
if (time < 0 || time > short.MaxValue)
time = 60;
@@ -4467,7 +5075,7 @@ namespace TShockAPI
}
if (args.Parameters.Count == 3)
int.TryParse(args.Parameters[2], out time);
- if (id > 0 && id < Main.maxBuffs)
+ if (id > 0 && id < Main.maxBuffTypes)
{
if (time < 0 || time > short.MaxValue)
time = 60;
@@ -4494,6 +5102,13 @@ namespace TShockAPI
var name = "Fail";
var x = args.Player.TileX;
var y = args.Player.TileY + 3;
+
+ if (!TShock.Regions.CanBuild(x, y, args.Player))
+ {
+ args.Player.SendErrorMessage("You're not allowed to change tiles here!");
+ return;
+ }
+
switch (args.Parameters[0].ToLower())
{
case "tree":
diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs
index bebfc148..2b4726d8 100755
--- a/TShockAPI/ConfigFile.cs
+++ b/TShockAPI/ConfigFile.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -31,262 +31,372 @@ namespace TShockAPI
{
[Description(
"The equation for calculating invasion size is 100 + (multiplier * (number of active players with greater than 200 health))."
- )] public int InvasionMultiplier = 1;
+ )]
+ public int InvasionMultiplier = 1;
- [Description("The default maximum mobs that will spawn per wave. Higher means more mobs in that wave.")] public int
- DefaultMaximumSpawns = 5;
+ [Description("The default maximum mobs that will spawn per wave. Higher means more mobs in that wave.")]
+ public int DefaultMaximumSpawns = 5;
- [Description("The delay between waves. Lower values lead to more mobs.")] public int DefaultSpawnRate = 600;
- [Description("The port the server runs on.")] public int ServerPort = 7777;
- [Description("Enable or disable the whitelist based on IP addresses in whitelist.txt")] public bool EnableWhitelist;
+ [Description("The delay between waves. Lower values lead to more mobs.")]
+ public int DefaultSpawnRate = 600;
+ [Description("The port the server runs on.")]
+ public int ServerPort = 7777;
+ [Description("Enable or disable the whitelist based on IP addresses in whitelist.txt")]
+ public bool EnableWhitelist;
[Description(
"Enable the ability for invasion size to never decrease. Make sure to run /invade, and note that this adds 2 million+ goblins to the spawn queue for the map."
- )] public bool InfiniteInvasion;
+ )]
+ public bool InfiniteInvasion;
- [Description("Set the server pvp mode. Valid types are, \"normal\", \"always\", and \"disabled.\"")] public string PvPMode
+ [Description("Set the server pvp mode. Valid types are, \"normal\", \"always\", and \"disabled.\"")]
+ public string PvPMode
= "normal";
- [Description("Prevents tiles from being placed within SpawnProtectionRadius of the default spawn.")] public bool
- SpawnProtection = true;
+ [Description("Prevents tiles from being placed within SpawnProtectionRadius of the default spawn.")]
+ public bool SpawnProtection = true;
- [Description("Radius from spawn tile for SpawnProtection.")] public int SpawnProtectionRadius = 10;
+ [Description("Radius from spawn tile for SpawnProtection.")]
+ public int SpawnProtectionRadius = 10;
[Description(
"Max slots for the server. If you want people to be kicked with \"Server is full\" set this to how many players you want max and then set Terraria max players to 2 higher."
- )] public int MaxSlots = 8;
+ )]
+ public int MaxSlots = 8;
- [Description("Global protection agent for any block distance based anti-grief check.")] public bool RangeChecks = true;
- [Description("Disables any building; placing of blocks")] public bool DisableBuild;
+ [Description("Global protection agent for any block distance based anti-grief check.")]
+ public bool RangeChecks = true;
+ [Description("Disables any building; placing of blocks")]
+ public bool DisableBuild;
- [Description("#.#.#. = Red/Blue/Green - RGB Colors for the Admin Chat Color. Max value: 255")] public float[]
- SuperAdminChatRGB = {255, 0, 0};
+ [Description("#.#.#. = Red/Blue/Green - RGB Colors for the Admin Chat Color. Max value: 255")]
+ public float[] SuperAdminChatRGB = { 255, 0, 0 };
- [Description("Super admin group chat prefix")] public string SuperAdminChatPrefix = "(Admin) ";
- [Description("Super admin group chat suffix")] public string SuperAdminChatSuffix = "";
+ [Description("Super admin group chat prefix")]
+ public string SuperAdminChatPrefix = "(Admin) ";
+ [Description("Super admin group chat suffix")]
+ public string SuperAdminChatSuffix = "";
[Description(
- "Backup frequency in minutes. So, a value of 60 = 60 minutes. Backups are stored in the \\tshock\\backups folder.")] public int BackupInterval;
+ "Backup frequency in minutes. So, a value of 60 = 60 minutes. Backups are stored in the \\tshock\\backups folder.")]
+ public int BackupInterval;
- [Description("How long backups are kept in minutes. 2880 = 2 days.")] public int BackupKeepFor = 60;
+ [Description("How long backups are kept in minutes. 2880 = 2 days.")]
+ public int BackupKeepFor = 60;
[Description(
"Remembers where a player left off. It works by remembering the IP, NOT the character. \neg. When you try to disconnect, and reconnect to be automatically placed at spawn, you'll be at your last location. Note: Won't save after server restarts."
- )] public bool RememberLeavePos;
+ )]
+ public bool RememberLeavePos;
- [Description("Hardcore players ONLY. This means softcore players cannot join.")] public bool HardcoreOnly;
- [Description("Mediumcore players ONLY. This means softcore players cannot join.")] public bool MediumcoreOnly;
- [Description("Kicks a hardcore player on death.")] public bool KickOnMediumcoreDeath;
- [Description("Bans a hardcore player on death.")] public bool BanOnMediumcoreDeath;
+ [Description("Hardcore players ONLY. This means softcore players cannot join.")]
+ public bool HardcoreOnly;
+ [Description("Mediumcore players ONLY. This means softcore players cannot join.")]
+ public bool MediumcoreOnly;
+ [Description("Kicks a mediumcore player on death.")]
+ public bool KickOnMediumcoreDeath;
+ [Description("Bans a mediumcore player on death.")]
+ public bool BanOnMediumcoreDeath;
- [Description("Enable/disable Terraria's built in auto save.")] public bool AutoSave = true;
- [Description("Enable/disable save announcements.")] public bool AnnounceSave = true;
+ [Description("Enable/disable Terraria's built in auto save.")]
+ public bool AutoSave = true;
+ [Description("Enable/disable save announcements.")]
+ public bool AnnounceSave = true;
- [Description("Number of failed login attempts before kicking the player.")] public int MaximumLoginAttempts = 3;
+ [Description("Number of failed login attempts before kicking the player.")]
+ public int MaximumLoginAttempts = 3;
- [Description("Not implemented.")] public string RconPassword = "";
- [Description("Not implemented.")] public int RconPort = 7777;
+ [Description("Not implemented.")]
+ public string RconPassword = "";
+ [Description("Not implemented.")]
+ public int RconPort = 7777;
- [Description("Used when replying to a rest /status request or sent to the client when UseServerName is true.")] public string ServerName = "";
- [Description("Sends ServerName in place of the world name to clients.")] public bool UseServerName = false;
- [Description("Not implemented.")] public string MasterServer = "127.0.0.1";
+ [Description("Used when replying to a rest /status request or sent to the client when UseServerName is true.")]
+ public string ServerName = "";
+ [Description("Sends ServerName in place of the world name to clients.")]
+ public bool UseServerName = false;
+ [Description("Not implemented.")]
+ public string MasterServer = "127.0.0.1";
- [Description("Valid types are \"sqlite\" and \"mysql\"")] public string StorageType = "sqlite";
+ [Description("Valid types are \"sqlite\" and \"mysql\"")]
+ public string StorageType = "sqlite";
- [Description("The MySQL hostname and port to direct connections to")] public string MySqlHost = "localhost:3306";
- [Description("Database name to connect to")] public string MySqlDbName = "";
- [Description("Database username to connect with")] public string MySqlUsername = "";
- [Description("Database password to connect with")] public string MySqlPassword = "";
+ [Description("The MySQL hostname and port to direct connections to")]
+ public string MySqlHost = "localhost:3306";
+ [Description("Database name to connect to")]
+ public string MySqlDbName = "";
+ [Description("Database username to connect with")]
+ public string MySqlUsername = "";
+ [Description("Database password to connect with")]
+ public string MySqlPassword = "";
- [Description("Bans a mediumcore player on death.")] public string MediumcoreBanReason = "Death results in a ban";
- [Description("Kicks a mediumcore player on death.")] public string MediumcoreKickReason = "Death results in a kick";
+ [Description("Bans a mediumcore player on death.")]
+ public string MediumcoreBanReason = "Death results in a ban";
+ [Description("Kicks a mediumcore player on death.")]
+ public string MediumcoreKickReason = "Death results in a kick";
- [Description("Enables DNS resolution of incoming connections with GetGroupForIPExpensive.")] public bool
- EnableDNSHostResolution;
+ [Description("Enables DNS resolution of incoming connections with GetGroupForIPExpensive.")]
+ public bool EnableDNSHostResolution;
- [Description("Enables kicking of banned users by matching their IP Address.")] public bool EnableIPBans = true;
+ [Description("Enables kicking of banned users by matching their IP Address.")]
+ public bool EnableIPBans = true;
- [Description("Enables kicking of banned users by matching their client UUID.")] public bool EnableUUIDBans = true;
+ [Description("Enables kicking of banned users by matching their client UUID.")]
+ public bool EnableUUIDBans = true;
- [Description("Enables kicking of banned users by matching their Character Name.")] public bool EnableBanOnUsernames;
+ [Description("Enables kicking of banned users by matching their Character Name.")]
+ public bool EnableBanOnUsernames;
- [Description("Selects the default group name to place new registrants under.")] public string
- DefaultRegistrationGroupName = "default";
+ [Description("Selects the default group name to place new registrants under.")]
+ public string DefaultRegistrationGroupName = "default";
- [Description("Selects the default group name to place non registered users under")] public string
- DefaultGuestGroupName = "guest";
+ [Description("Selects the default group name to place non registered users under")]
+ public string DefaultGuestGroupName = "guest";
- [Description("Force-disable printing logs to players with the log permission.")] public bool DisableSpewLogs = true;
+ [Description("Force-disable printing logs to players with the log permission.")]
+ public bool DisableSpewLogs = true;
- [Description("Valid types are \"sha512\", \"sha256\", \"md5\", append with \"-xp\" for the xp supported algorithms.")] public string HashAlgorithm = "sha512";
+ [Description("Valid types are \"sha512\", \"sha256\", \"md5\", append with \"-xp\" for the xp supported algorithms.")]
+ public string HashAlgorithm = "sha512";
- [Description("Buffers up the packets and sends them out at the end of each frame.")] public bool BufferPackets = true;
+ [Description("Buffers up the packets and sends them out at the end of each frame.")]
+ public bool BufferPackets = true;
- [Description("String that is used when kicking people when the server is full.")] public string ServerFullReason =
- "Server is full";
+ [Description("String that is used when kicking people when the server is full.")]
+ public string ServerFullReason = "Server is full";
- [Description("String that is used when a user is kicked due to not being on the whitelist.")] public string WhitelistKickReason = "You are not on the whitelist.";
+ [Description("String that is used when a user is kicked due to not being on the whitelist.")]
+ public string WhitelistKickReason = "You are not on the whitelist.";
- [Description("String that is used when kicking people when the server is full with no reserved slots.")] public string
- ServerFullNoReservedReason = "Server is full. No reserved slots open.";
+ [Description("String that is used when kicking people when the server is full with no reserved slots.")]
+ public string ServerFullNoReservedReason = "Server is full. No reserved slots open.";
- [Description("This will save the world if Terraria crashes from an unhandled exception.")] public bool
- SaveWorldOnCrash = true;
+ [Description("This will save the world if Terraria crashes from an unhandled exception.")]
+ public bool SaveWorldOnCrash = true;
- [Description("This will announce a player's location on join")] public bool EnableGeoIP;
+ [Description("This will announce a player's location on join")]
+ public bool EnableGeoIP;
- [Description("This will turn on token requirement for the public REST API endpoints.")] public bool
- EnableTokenEndpointAuthentication;
+ [Description("This will turn on token requirement for the public REST API endpoints.")]
+ public bool EnableTokenEndpointAuthentication;
- [Description("Enable/disable the rest api.")] public bool RestApiEnabled;
+ [Description("Enable/disable the rest api.")]
+ public bool RestApiEnabled;
- [Description("This is the port which the rest api will listen on.")] public int RestApiPort = 7878;
+ [Description("This is the port which the rest api will listen on.")]
+ public int RestApiPort = 7878;
- [Description("Disable tombstones for all players.")] public bool DisableTombstones = true;
+ [Description("Disable tombstones for all players.")]
+ public bool DisableTombstones = true;
- [Description("Displays a player's IP on join to everyone who has the log permission.")] public bool DisplayIPToAdmins;
+ [Description("Displays a player's IP on join to everyone who has the log permission.")]
+ public bool DisplayIPToAdmins;
- [Description("Kicks users using a proxy as identified with the GeoIP database.")] public bool KickProxyUsers = true;
+ [Description("Kicks users using a proxy as identified with the GeoIP database.")]
+ public bool KickProxyUsers = true;
- [Description("Disables hardmode, can't never be activated. Overrides /starthardmode.")] public bool DisableHardmode;
+ [Description("Disables hardmode, can't never be activated. Overrides /starthardmode.")]
+ public bool DisableHardmode;
- [Description("Disables the dungeon guardian from being spawned by player packets, this will instead force a respawn.")] public bool DisableDungeonGuardian;
+ [Description("Disables the dungeon guardian from being spawned by player packets, this will instead force a respawn.")]
+ public bool DisableDungeonGuardian;
- [Description("Enable server side characters, This stops the client from saving character data! EXPERIMENTAL!!!!!")] public bool ServerSideCharacter;
+ [Description("Disables clown bomb projectiles from spawning.")]
+ public bool DisableClownBombs;
- [Description("How often SSC should save, in minutes.")] public int ServerSideCharacterSave = 5;
-
- [Description("Time, in milliseconds, to disallow discarding items after logging in when ServerSideInventory is ON.")] public int LogonDiscardThreshold=250;
-
- [Description("Disables clown bomb projectiles from spawning.")] public bool DisableClownBombs;
-
- [Description("Disables snow ball projectiles from spawning.")] public bool DisableSnowBalls;
+ [Description("Disables snow ball projectiles from spawning.")]
+ public bool DisableSnowBalls;
[Description(
"Changes ingame chat format: {0} = Group Name, {1} = Group Prefix, {2} = Player Name, {3} = Group Suffix, {4} = Chat Message"
- )] public string ChatFormat = "{1}{2}{3}: {4}";
+ )]
+ public string ChatFormat = "{1}{2}{3}: {4}";
- [Description("Change the player name when using chat above heads. This begins with a player name wrapped in brackets, as per Terraria's formatting. Same formatting as ChatFormat(minus the text aka {4}).")] public string ChatAboveHeadsFormat = "{2}";
+ [Description("Change the player name when using chat above heads. This begins with a player name wrapped in brackets, as per Terraria's formatting. Same formatting as ChatFormat(minus the text aka {4}).")]
+ public string ChatAboveHeadsFormat = "{2}";
- [Description("Force the world time to be normal, day, or night.")] public string ForceTime = "normal";
+ [Description("Force the world time to be normal, day, or night.")]
+ public string ForceTime = "normal";
- [Description("Disables/reverts a player if this number of tile kills is exceeded within 1 second.")] public int
- TileKillThreshold = 60;
+ [Description("Disables/reverts a player if this number of tile kills is exceeded within 1 second.")]
+ public int TileKillThreshold = 60;
- [Description("Disables/reverts a player if this number of tile places is exceeded within 1 second.")]
- public int
- TilePlaceThreshold = 20;
+ [Description("Disables/reverts a player if this number of tile places is exceeded within 1 second.")]
+ public int TilePlaceThreshold = 20;
- [Description("Disables a player if this number of liquid sets is exceeded within 1 second.")] public int
- TileLiquidThreshold = 15;
+ [Description("Disables a player if this number of liquid sets is exceeded within 1 second.")]
+ public int TileLiquidThreshold = 15;
- [Description("Disable a player if this number of projectiles is created within 1 second.")]
- public int
- ProjectileThreshold = 50;
+ [Description("Disable a player if this number of projectiles is created within 1 second.")]
+ public int ProjectileThreshold = 50;
- [Description("Ignore shrapnel from crystal bullets for projectile threshold.")] public bool
- ProjIgnoreShrapnel = true;
-
- [Description("Requires all players to register or login before being allowed to play.")] public bool RequireLogin;
+ [Description("Ignore shrapnel from crystal bullets for projectile threshold.")]
+ public bool ProjIgnoreShrapnel = true;
+
+ [Description("Requires all players to register or login before being allowed to play.")]
+ public bool RequireLogin;
[Description(
"Disables invisibility potions from being used in PvP (Note, can be used in the client, but the effect isn't sent to the rest of the server)."
- )] public bool DisableInvisPvP;
+ )]
+ public bool DisableInvisPvP;
- [Description("The maximum distance players disabled for various reasons can move from.")] public int
- MaxRangeForDisabled = 10;
+ [Description("The maximum distance players disabled for various reasons can move from.")]
+ public int MaxRangeForDisabled = 10;
- [Description("Server password required to join the server.")] public string ServerPassword = "";
+ [Description("Server password required to join the server.")]
+ public string ServerPassword = "";
- [Description("Protect chests with region and build permissions.")] public bool RegionProtectChests;
+ [Description("Protect chests with region and build permissions.")]
+ public bool RegionProtectChests;
- [Description("Disable users from being able to login with account password when joining.")] public bool
- DisableLoginBeforeJoin;
+ [Description("Disable users from being able to login with account password when joining.")]
+ public bool DisableLoginBeforeJoin;
- [Description("Disable users from being able to login with their client UUID.")] public bool DisableUUIDLogin;
+ [Description("Disable users from being able to login with their client UUID.")]
+ public bool DisableUUIDLogin;
- [Description("Kick clients that don't send a UUID to the server.")] public bool KickEmptyUUID;
-
- [Description("Allows users to register any username with /register.")] public bool AllowRegisterAnyUsername;
+ [Description("Kick clients that don't send a UUID to the server.")]
+ public bool KickEmptyUUID;
- [Description("Allows users to login with any username with /login.")] public bool AllowLoginAnyUsername = true;
+ [Description("Allows users to register any username with /register.")]
+ public bool AllowRegisterAnyUsername;
- [Description("The maximum damage a player/npc can inflict.")] public int MaxDamage = 175;
-
- [Description("The maximum damage a projectile can inflict.")] public int MaxProjDamage = 175;
+ [Description("Allows users to login with any username with /login.")]
+ public bool AllowLoginAnyUsername = true;
- [Description("Ignores checking to see if player 'can' update a projectile.")] public bool IgnoreProjUpdate = false;
-
- [Description("Ignores checking to see if player 'can' kill a projectile.")] public bool IgnoreProjKill = false;
+ [Description("The maximum damage a player/npc can inflict.")]
+ public int MaxDamage = 175;
- [Description("Ignores all no clip checks for players.")] public bool IgnoreNoClip = false;
+ [Description("The maximum damage a projectile can inflict.")]
+ public int MaxProjDamage = 175;
- [Description("Allow ice placement even when user does not have canbuild.")] public bool AllowIce = false;
+ [Description("Kicks a user if set to true, if they inflict more damage then the max damage.")]
+ public bool KickOnDamageThresholdBroken = false;
+
+ [Description("Ignores checking to see if player 'can' update a projectile.")]
+ public bool IgnoreProjUpdate = false;
+
+ [Description("Ignores checking to see if player 'can' kill a projectile.")]
+ public bool IgnoreProjKill = false;
+
+ [Description("Ignores all no clip checks for players.")]
+ public bool IgnoreNoClip = false;
+
+ [Description("Allow ice placement even when user does not have canbuild.")]
+ public bool AllowIce = false;
[Description("Allows crimson to spread when a world is hardmode.")]
public bool AllowCrimsonCreep = true;
- [Description("Allows corruption to spread when a world is hardmode.")] public bool AllowCorruptionCreep = true;
+ [Description("Allows corruption to spread when a world is hardmode.")]
+ public bool AllowCorruptionCreep = true;
- [Description("Allows hallow to spread when a world is hardmode.")] public bool AllowHallowCreep = true;
+ [Description("Allows hallow to spread when a world is hardmode.")]
+ public bool AllowHallowCreep = true;
- [Description("How many things a statue can spawn within 200 pixels(?) before it stops spawning. Default = 3")] public int StatueSpawn200 = 3;
+ [Description("How many things a statue can spawn within 200 pixels(?) before it stops spawning. Default = 3")]
+ public int StatueSpawn200 = 3;
- [Description("How many things a statue can spawn within 600 pixels(?) before it stops spawning. Default = 6")] public int StatueSpawn600 = 6;
+ [Description("How many things a statue can spawn within 600 pixels(?) before it stops spawning. Default = 6")]
+ public int StatueSpawn600 = 6;
- [Description("How many things a statue spawns can exist in the world before it stops spawning. Default = 10")] public int StatueSpawnWorld = 10;
+ [Description("How many things a statue spawns can exist in the world before it stops spawning. Default = 10")]
+ public int StatueSpawnWorld = 10;
- [Description("Prevent banned items from being /i or /give.")] public bool PreventBannedItemSpawn = false;
+ [Description("Prevent banned items from being /i or /give.")]
+ public bool PreventBannedItemSpawn = false;
- [Description("Prevent players from interacting with the world if dead.")] public bool PreventDeadModification =
- true;
+ [Description("Prevent players from interacting with the world if dead.")]
+ public bool PreventDeadModification = true;
- [Description("Displays chat messages above players' heads, but will disable chat prefixes to compensate.")] public
- bool EnableChatAboveHeads = false;
+ [Description("Displays chat messages above players' heads, but will disable chat prefixes to compensate.")]
+ public bool EnableChatAboveHeads = false;
- [Description("Force Christmas only events to occur all year.")] public bool ForceXmas = false;
+ [Description("Force Christmas-only events to occur all year.")]
+ public bool ForceXmas = false;
- [Description("Allows groups on the banned item allowed list to spawn banned items.")] public bool AllowAllowedGroupsToSpawnBannedItems = false;
+ [Description("Allows groups on the banned item allowed list to spawn banned items.")]
+ public bool AllowAllowedGroupsToSpawnBannedItems = false;
- [Description("Allows stacks in chests to be beyond the stack limit")] public bool IgnoreChestStacksOnLoad = false;
+ [Description("Allows stacks in chests to be beyond the stack limit")]
+ public bool IgnoreChestStacksOnLoad = false;
- [Description("The path of the directory where logs should be written into.")] public string LogPath = "tshock";
+ [Description("The path of the directory where logs should be written into.")]
+ public string LogPath = "tshock";
- [Description("Prevents players from placing tiles with an invalid style.")] public bool PreventInvalidPlaceStyle = true;
+ [Description("Prevents players from placing tiles with an invalid style.")]
+ public bool PreventInvalidPlaceStyle = true;
- [Description("#.#.#. = Red/Blue/Green - RGB Colors for broadcasts. Max value: 255.")] public float[] BroadcastRGB =
- {127,255,212};
+ [Description("#.#.#. = Red/Blue/Green - RGB Colors for broadcasts. Max value: 255.")]
+ public float[] BroadcastRGB = { 127, 255, 212 };
// TODO: Get rid of this when the old REST permission model is removed.
[Description(
"Whether the REST API should use the new permission model. Note: The old permission model will become depracted in the future."
- )] public bool RestUseNewPermissionModel = true;
+ )]
+ public bool RestUseNewPermissionModel = true;
- [Description("A dictionary of REST tokens that external applications may use to make queries to your server.")]
- public Dictionary ApplicationRestTokens = new Dictionary();
+ [Description("A dictionary of REST tokens that external applications may use to make queries to your server.")]
+ public Dictionary ApplicationRestTokens = new Dictionary();
- [Description("The number of reserved slots past your max server slot that can be joined by reserved players")] public int ReservedSlots = 20;
+ [Description("The number of reserved slots past your max server slot that can be joined by reserved players")]
+ public int ReservedSlots = 20;
+
+ [Description("The number of reserved slots past your max server slot that can be joined by reserved players")]
+ public bool LogRest = false;
+
+ [Description("The number of seconds a player must wait before being respawned.")]
+ public int RespawnSeconds = 5;
+
+ [Description("The number of seconds a player must wait before being respawned if there is a boss nearby.")]
+ public int RespawnBossSeconds = 10;
+
+ [Description("Disables a player if this number of tiles is painted within 1 second.")]
+ public int TilePaintThreshold = 15;
+
+ [Description("Enables max packet bufferer size.")]
+ public bool EnableMaxBytesInBuffer = false;
+
+ [Description("Number of bytes in the packet buffer before we disconnect the player.")]
+ public int MaxBytesInBuffer = 5242880;
+
+ [Description("Forces your world to be in Halloween mode regardless of the data.")]
+ public bool ForceHalloween = false;
+
+ [Description("Allows anyone to break grass, pots, etc.")]
+ public bool AllowCutTilesAndBreakables = false;
+
+ [Description("Specifies which string starts a command")]
+ public string CommandSpecifier = "/";
- [Description("The number of reserved slots past your max server slot that can be joined by reserved players")] public bool LogRest = false;
+ [Description("Kicks a hardcore player on death.")]
+ public bool KickOnHardcoreDeath;
+
+ [Description("Bans a hardcore player on death.")]
+ public bool BanOnHardcoreDeath;
+
+ [Description("Bans a hardcore player on death.")]
+ public string HardcoreBanReason = "Death results in a ban";
+
+ [Description("Kicks a hardcore player on death.")]
+ public string HardcoreKickReason = "Death results in a kick";
- [Description("The number of seconds a player must wait before being respawned.")] public int RespawnSeconds = 3;
+ [Description("Whether bosses or invasions should be anonymously spawned.")]
+ public bool AnonymousBossInvasions = true;
- [Description("Disables a player if this number of tiles is painted within 1 second.")] public int TilePaintThreshold = 15;
+ [Description("The maximum allowable HP, before equipment buffs.")]
+ public int MaxHP = 500;
- [Description("Enables max packet bufferer size.")] public bool EnableMaxBytesInBuffer = false;
+ [Description("The maximum allowable MP, before equipment buffs.")]
+ public int MaxMP = 200;
- [Description("Number of bytes in the packet buffer before we disconnect the player.")] public int MaxBytesInBuffer = 5242880;
-
- [Description("Forces your world to be in Halloween mode regardless of the data.")] public bool ForceHalloween = false;
-
- [Description("Allows anyone to break grass, pots, etc.")] public bool AllowCutTilesAndBreakables = false;
-
- ///
- /// Reads a configuration file from a given path
- ///
- /// string path
- /// ConfigFile object
- public static ConfigFile Read(string path)
+ ///
+ /// Reads a configuration file from a given path
+ ///
+ /// string path
+ /// ConfigFile object
+ public static ConfigFile Read(string path)
{
if (!File.Exists(path))
return new ConfigFile();
@@ -296,11 +406,11 @@ namespace TShockAPI
}
}
- ///
- /// Reads the configuration file from a stream
- ///
- /// stream
- /// ConfigFile object
+ ///
+ /// Reads the configuration file from a stream
+ ///
+ /// stream
+ /// ConfigFile object
public static ConfigFile Read(Stream stream)
{
using (var sr = new StreamReader(stream))
@@ -312,10 +422,10 @@ namespace TShockAPI
}
}
- ///
- /// Writes the configuration to a given path
- ///
- /// string path - Location to put the config file
+ ///
+ /// Writes the configuration to a given path
+ ///
+ /// string path - Location to put the config file
public void Write(string path)
{
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write))
@@ -324,10 +434,10 @@ namespace TShockAPI
}
}
- ///
- /// Writes the configuration to a stream
- ///
- /// stream
+ ///
+ /// Writes the configuration to a stream
+ ///
+ /// stream
public void Write(Stream stream)
{
var str = JsonConvert.SerializeObject(this, Formatting.Indented);
@@ -337,14 +447,14 @@ namespace TShockAPI
}
}
- ///
- /// On config read hook
- ///
+ ///
+ /// On config read hook
+ ///
public static Action ConfigRead;
- ///
- /// Dumps all configuration options to a text file in Markdown format
- ///
+ ///
+ /// Dumps all configuration options to a text file in Markdown format
+ ///
public static void DumpDescriptions()
{
var sb = new StringBuilder();
diff --git a/TShockAPI/DB/BanManager.cs b/TShockAPI/DB/BanManager.cs
index 6f6adf5b..89a62c99 100644
--- a/TShockAPI/DB/BanManager.cs
+++ b/TShockAPI/DB/BanManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -232,7 +232,7 @@ namespace TShockAPI.DB
{
IP = ip;
Name = name;
- UUID = UUID;
+ UUID = uuid;
Reason = reason;
BanningUser = banner;
Date = date;
diff --git a/TShockAPI/DB/CharacterManager.cs b/TShockAPI/DB/CharacterManager.cs
index c0c0a6d7..a1f6b5b2 100755
--- a/TShockAPI/DB/CharacterManager.cs
+++ b/TShockAPI/DB/CharacterManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -18,7 +18,9 @@ along with this program. If not, see .
using System;
using System.Data;
+using System.Text;
using MySql.Data.MySqlClient;
+using Terraria;
namespace TShockAPI.DB
{
@@ -38,7 +40,18 @@ namespace TShockAPI.DB
new SqlColumn("MaxMana", MySqlDbType.Int32),
new SqlColumn("Inventory", MySqlDbType.Text),
new SqlColumn("spawnX", MySqlDbType.Int32),
- new SqlColumn("spawnY", MySqlDbType.Int32)
+ new SqlColumn("spawnY", MySqlDbType.Int32),
+ new SqlColumn("hair", MySqlDbType.Int32),
+ new SqlColumn("hairDye", MySqlDbType.Int32),
+ new SqlColumn("hairColor", MySqlDbType.Int32),
+ new SqlColumn("pantsColor", MySqlDbType.Int32),
+ new SqlColumn("shirtColor", MySqlDbType.Int32),
+ new SqlColumn("underShirtColor", MySqlDbType.Int32),
+ new SqlColumn("shoeColor", MySqlDbType.Int32),
+ new SqlColumn("hideVisuals", MySqlDbType.Int32),
+ new SqlColumn("skinColor", MySqlDbType.Int32),
+ new SqlColumn("eyeColor", MySqlDbType.Int32),
+ new SqlColumn("questsCompleted", MySqlDbType.Int32)
);
var creator = new SqlTableCreator(db,
db.GetSqlType() == SqlType.Sqlite
@@ -65,6 +78,17 @@ namespace TShockAPI.DB
playerData.inventory = NetItem.Parse(reader.Get("Inventory"));
playerData.spawnX = reader.Get("spawnX");
playerData.spawnY = reader.Get("spawnY");
+ playerData.hair = reader.Get("hair");
+ playerData.hairDye = (byte)reader.Get("hairDye");
+ playerData.hairColor = TShock.Utils.DecodeColor(reader.Get("hairColor"));
+ playerData.pantsColor = TShock.Utils.DecodeColor(reader.Get("pantsColor"));
+ playerData.shirtColor = TShock.Utils.DecodeColor(reader.Get("shirtColor"));
+ playerData.underShirtColor = TShock.Utils.DecodeColor(reader.Get("underShirtColor"));
+ playerData.shoeColor = TShock.Utils.DecodeColor(reader.Get("shoeColor"));
+ playerData.hideVisuals = TShock.Utils.DecodeBitsByte(reader.Get("hideVisuals"));
+ playerData.skinColor = TShock.Utils.DecodeColor(reader.Get("skinColor"));
+ playerData.eyeColor = TShock.Utils.DecodeColor(reader.Get("eyeColor"));
+ playerData.questsCompleted = reader.Get("questsCompleted");
return playerData;
}
}
@@ -79,11 +103,36 @@ namespace TShockAPI.DB
public bool SeedInitialData(User user)
{
- string initialItems = "-15,1,0~-13,1,0~-16,1,45~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0~0,0,0";
+ var inventory = new StringBuilder();
+ for (int i = 0; i < Terraria.Main.maxInventory; i++)
+ {
+ if (i > 0)
+ {
+ inventory.Append("~");
+ }
+ if (i < TShock.ServerSideCharacterConfig.StartingInventory.Count)
+ {
+ var item = TShock.ServerSideCharacterConfig.StartingInventory[i];
+ inventory.Append(item.netID).Append(',').Append(item.stack).Append(',').Append(item.prefix);
+ }
+ else
+ {
+ inventory.Append("0,0,0");
+ }
+ }
+ string initialItems = inventory.ToString();
try
{
- database.Query("INSERT INTO tsCharacter (Account, Health, MaxHealth, Mana, MaxMana, Inventory, spawnX, spawnY) VALUES (@0, @1, @2, @3, @4, @5, @6, @7);", user.ID,
- 100, 100, 20, 20, initialItems, -1, -1);
+ database.Query("INSERT INTO tsCharacter (Account, Health, MaxHealth, Mana, MaxMana, Inventory, spawnX, spawnY, questsCompleted) VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8);",
+ user.ID,
+ TShock.ServerSideCharacterConfig.StartingHealth,
+ TShock.ServerSideCharacterConfig.StartingHealth,
+ TShock.ServerSideCharacterConfig.StartingMana,
+ TShock.ServerSideCharacterConfig.StartingMana,
+ initialItems,
+ -1,
+ -1,
+ 0);
return true;
}
catch (Exception ex)
@@ -106,8 +155,9 @@ namespace TShockAPI.DB
{
try
{
- database.Query("INSERT INTO tsCharacter (Account, Health, MaxHealth, Mana, MaxMana, Inventory, spawnX, spawnY) VALUES (@0, @1, @2, @3, @4, @5, @6, @7);", player.UserID,
- playerData.health, playerData.maxHealth, playerData.mana, playerData.maxMana, NetItem.ToString(playerData.inventory), player.TPlayer.SpawnX, player.TPlayer.SpawnY);
+ database.Query(
+ "INSERT INTO tsCharacter (Account, Health, MaxHealth, Mana, MaxMana, Inventory, spawnX, spawnY, hair, hairDye, hairColor, pantsColor, shirtColor, underShirtColor, shoeColor, hideVisuals, skinColor, eyeColor, questsCompleted) VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16, @17, @18);",
+ player.UserID, playerData.health, playerData.maxHealth, playerData.mana, playerData.maxMana, NetItem.ToString(playerData.inventory), player.TPlayer.SpawnX, player.TPlayer.SpawnY, player.TPlayer.hair, player.TPlayer.hairDye, TShock.Utils.EncodeColor(player.TPlayer.hairColor), TShock.Utils.EncodeColor(player.TPlayer.pantsColor),TShock.Utils.EncodeColor(player.TPlayer.shirtColor), TShock.Utils.EncodeColor(player.TPlayer.underShirtColor), TShock.Utils.EncodeColor(player.TPlayer.shoeColor), TShock.Utils.EncodeBitsByte(player.TPlayer.hideVisual), TShock.Utils.EncodeColor(player.TPlayer.skinColor),TShock.Utils.EncodeColor(player.TPlayer.eyeColor), player.TPlayer.anglerQuestsFinished);
return true;
}
catch (Exception ex)
@@ -119,8 +169,9 @@ namespace TShockAPI.DB
{
try
{
- database.Query("UPDATE tsCharacter SET Health = @0, MaxHealth = @1, Mana = @2, MaxMana = @3, Inventory = @4, spawnX = @6, spawnY = @7 WHERE Account = @5;", playerData.health, playerData.maxHealth,
- playerData.mana, playerData.maxMana, NetItem.ToString(playerData.inventory), player.UserID, player.TPlayer.SpawnX, player.TPlayer.SpawnY);
+ database.Query(
+ "UPDATE tsCharacter SET Health = @0, MaxHealth = @1, Mana = @2, MaxMana = @3, Inventory = @4, spawnX = @6, spawnY = @7, hair = @8, hairDye = @9, hairColor = @10, pantsColor = @11, shirtColor = @12, underShirtColor = @13, shoeColor = @14, hideVisuals = @15, skinColor = @16, eyeColor = @17, questsCompleted = @18 WHERE Account = @5;",
+ playerData.health, playerData.maxHealth, playerData.mana, playerData.maxMana, NetItem.ToString(playerData.inventory), player.UserID, player.TPlayer.SpawnX, player.TPlayer.SpawnY, player.TPlayer.hair, player.TPlayer.hairDye, TShock.Utils.EncodeColor(player.TPlayer.hairColor), TShock.Utils.EncodeColor(player.TPlayer.pantsColor), TShock.Utils.EncodeColor(player.TPlayer.shirtColor), TShock.Utils.EncodeColor(player.TPlayer.underShirtColor), TShock.Utils.EncodeColor(player.TPlayer.shoeColor), TShock.Utils.EncodeBitsByte(player.TPlayer.hideVisual), TShock.Utils.EncodeColor(player.TPlayer.skinColor), TShock.Utils.EncodeColor(player.TPlayer.eyeColor), player.TPlayer.anglerQuestsFinished);
return true;
}
catch (Exception ex)
@@ -146,4 +197,4 @@ namespace TShockAPI.DB
return false;
}
}
-}
\ No newline at end of file
+}
diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs
index 7a00523b..cd0f6d87 100644
--- a/TShockAPI/DB/GroupManager.cs
+++ b/TShockAPI/DB/GroupManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -67,7 +67,7 @@ namespace TShockAPI.DB
string.Join(",", Permissions.ban, Permissions.whitelist, "tshock.world.time.*", Permissions.spawnboss,
Permissions.spawnmob, Permissions.managewarp, Permissions.time, Permissions.tp, Permissions.slap,
Permissions.kill, Permissions.logs,
- Permissions.immunetokick, Permissions.tphere));
+ Permissions.immunetokick, Permissions.tpothers));
AddDefaultGroup("trustedadmin", "admin",
string.Join(",", Permissions.maintenance, "tshock.cfg.*", "tshock.world.*", Permissions.butcher, Permissions.item,
diff --git a/TShockAPI/DB/IQueryBuilder.cs b/TShockAPI/DB/IQueryBuilder.cs
index ac38c86f..ac030759 100644
--- a/TShockAPI/DB/IQueryBuilder.cs
+++ b/TShockAPI/DB/IQueryBuilder.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -44,10 +44,15 @@ namespace TShockAPI.DB
var columns =
table.Columns.Select(
c =>
- "'{0}' {1} {2} {3} {4} {5}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "",
- c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : "",
- c.Unique ? "UNIQUE" : ""));
- return "CREATE TABLE {0} ({1})".SFormat(EscapeTableName(table.Name), string.Join(", ", columns));
+ "'{0}' {1} {2} {3} {4}".SFormat(c.Name,
+ DbTypeToString(c.Type, c.Length),
+ c.Primary ? "PRIMARY KEY" : "",
+ c.AutoIncrement ? "AUTOINCREMENT" : "",
+ c.NotNull ? "NOT NULL" : ""));
+ var uniques = table.Columns.Where(c => c.Unique).Select(c => c.Name);
+ return "CREATE TABLE {0} ({1} {2})".SFormat(EscapeTableName(table.Name),
+ string.Join(", ", columns),
+ uniques.Count() > 0 ? ", UNIQUE({0})".SFormat(string.Join(", ", uniques)) : "");
}
public override string RenameTable(string from, string to)
@@ -67,6 +72,7 @@ namespace TShockAPI.DB
{ MySqlDbType.Double, "REAL" },
{ MySqlDbType.Int32, "INTEGER" },
{ MySqlDbType.Blob, "BLOB" },
+ { MySqlDbType.Int64, "BIGINT"},
};
public string DbTypeToString(MySqlDbType type, int? length)
@@ -115,6 +121,7 @@ namespace TShockAPI.DB
{ MySqlDbType.Float, "FLOAT" },
{ MySqlDbType.Double, "DOUBLE" },
{ MySqlDbType.Int32, "INT" },
+ { MySqlDbType.Int64, "BIGINT"},
};
public string DbTypeToString(MySqlDbType type, int? length)
diff --git a/TShockAPI/DB/ItemManager.cs b/TShockAPI/DB/ItemManager.cs
index a43a40bb..141f2925 100644
--- a/TShockAPI/DB/ItemManager.cs
+++ b/TShockAPI/DB/ItemManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -101,12 +101,8 @@ namespace TShockAPI.DB
public bool ItemIsBanned(string name, TSPlayer ply)
{
- if (ItemBans.Contains(new ItemBan(name)))
- {
- ItemBan b = GetItemBanByName(name);
- return !b.HasPermissionToUseItem(ply);
- }
- return false;
+ ItemBan b = GetItemBanByName(name);
+ return b != null &&!b.HasPermissionToUseItem(ply);
}
public bool AllowGroup(string item, string name)
@@ -162,11 +158,11 @@ namespace TShockAPI.DB
public ItemBan GetItemBanByName(String name)
{
- foreach (ItemBan b in ItemBans)
+ for (int i = 0; i < ItemBans.Count; i++)
{
- if (b.Name == name)
+ if (ItemBans[i].Name == name)
{
- return b;
+ return ItemBans[i];
}
}
return null;
diff --git a/TShockAPI/DB/ProjectileManager.cs b/TShockAPI/DB/ProjectileManager.cs
new file mode 100644
index 00000000..a9cbf31b
--- /dev/null
+++ b/TShockAPI/DB/ProjectileManager.cs
@@ -0,0 +1,253 @@
+/*
+TShock, a server mod for Terraria
+Copyright (C) 2011-2015 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 .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using MySql.Data.MySqlClient;
+
+namespace TShockAPI.DB
+{
+ public class ProjectileManagager
+ {
+ private IDbConnection database;
+ public List ProjectileBans = new List();
+
+ public ProjectileManagager(IDbConnection db)
+ {
+ database = db;
+
+ var table = new SqlTable("ProjectileBans",
+ new SqlColumn("ProjectileID", MySqlDbType.Int32) {Primary = true},
+ new SqlColumn("AllowedGroups", MySqlDbType.Text)
+ );
+ var creator = new SqlTableCreator(db,
+ db.GetSqlType() == SqlType.Sqlite
+ ? (IQueryBuilder) new SqliteQueryCreator()
+ : new MysqlQueryCreator());
+ creator.EnsureExists(table);
+ UpdateBans();
+ }
+
+ public void UpdateBans()
+ {
+ ProjectileBans.Clear();
+
+ using (var reader = database.QueryReader("SELECT * FROM ProjectileBans"))
+ {
+ while (reader != null && reader.Read())
+ {
+ ProjectileBan ban = new ProjectileBan((short) reader.Get("ProjectileID"));
+ ban.SetAllowedGroups(reader.Get("AllowedGroups"));
+ ProjectileBans.Add(ban);
+ }
+ }
+ }
+
+ public void AddNewBan(short id = 0)
+ {
+ try
+ {
+ database.Query("INSERT INTO ProjectileBans (ProjectileID, AllowedGroups) VALUES (@0, @1);",
+ id, "");
+
+ if (!ProjectileIsBanned(id, null))
+ ProjectileBans.Add(new ProjectileBan(id));
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+
+ public void RemoveBan(short id)
+ {
+ if (!ProjectileIsBanned(id, null))
+ return;
+ try
+ {
+ database.Query("DELETE FROM ProjectileBans WHERE ProjectileId=@0;", id);
+ ProjectileBans.Remove(new ProjectileBan(id));
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+
+ public bool ProjectileIsBanned(short id)
+ {
+ if (ProjectileBans.Contains(new ProjectileBan(id)))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public bool ProjectileIsBanned(short id, TSPlayer ply)
+ {
+ if (ProjectileBans.Contains(new ProjectileBan(id)))
+ {
+ ProjectileBan b = GetBanById(id);
+ return !b.HasPermissionToCreateProjectile(ply);
+ }
+ return false;
+ }
+
+ public bool AllowGroup(short id, string name)
+ {
+ string groupsNew = "";
+ ProjectileBan b = GetBanById(id);
+ if (b != null)
+ {
+ try
+ {
+ groupsNew = String.Join(",", b.AllowedGroups);
+ if (groupsNew.Length > 0)
+ groupsNew += ",";
+ groupsNew += name;
+ b.SetAllowedGroups(groupsNew);
+
+ int q = database.Query("UPDATE ProjectileBans SET AllowedGroups=@0 WHERE ProjectileId=@1", groupsNew,
+ id);
+
+ return q > 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+
+ return false;
+ }
+
+ public bool RemoveGroup(short id, string group)
+ {
+ ProjectileBan b = GetBanById(id);
+ if (b != null)
+ {
+ try
+ {
+ b.RemoveGroup(group);
+ string groups = string.Join(",", b.AllowedGroups);
+ int q = database.Query("UPDATE ProjectileBans SET AllowedGroups=@0 WHERE ProjectileId=@1", groups,
+ id);
+
+ if (q > 0)
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+ return false;
+ }
+
+ public ProjectileBan GetBanById(short id)
+ {
+ foreach (ProjectileBan b in ProjectileBans)
+ {
+ if (b.ID == id)
+ {
+ return b;
+ }
+ }
+ return null;
+ }
+ }
+
+ public class ProjectileBan : IEquatable
+ {
+ public short ID { get; set; }
+ public List AllowedGroups { get; set; }
+
+ public ProjectileBan(short id)
+ : this()
+ {
+ ID = id;
+ AllowedGroups = new List();
+ }
+
+ public ProjectileBan()
+ {
+ ID = 0;
+ AllowedGroups = new List();
+ }
+
+ public bool Equals(ProjectileBan other)
+ {
+ return ID == other.ID;
+ }
+
+ public bool HasPermissionToCreateProjectile(TSPlayer ply)
+ {
+ if (ply == null)
+ return false;
+
+ if (ply.Group.HasPermission(Permissions.canusebannedprojectiles))
+ return true;
+
+ var cur = ply.Group;
+ var traversed = new List();
+ while (cur != null)
+ {
+ if (AllowedGroups.Contains(cur.Name))
+ {
+ return true;
+ }
+ if (traversed.Contains(cur))
+ {
+ throw new InvalidOperationException("Infinite group parenting ({0})".SFormat(cur.Name));
+ }
+ traversed.Add(cur);
+ cur = cur.Parent;
+ }
+ return false;
+ // could add in the other permissions in this class instead of a giant if switch.
+ }
+
+ public void SetAllowedGroups(String groups)
+ {
+ // prevent null pointer exceptions
+ if (!string.IsNullOrEmpty(groups))
+ {
+ List groupArr = groups.Split(',').ToList();
+
+ for (int i = 0; i < groupArr.Count; i++)
+ {
+ groupArr[i] = groupArr[i].Trim();
+ //Console.WriteLine(groupArr[i]);
+ }
+ AllowedGroups = groupArr;
+ }
+ }
+
+ public bool RemoveGroup(string groupName)
+ {
+ return AllowedGroups.Remove(groupName);
+ }
+
+ public override string ToString()
+ {
+ return ID + (AllowedGroups.Count > 0 ? " (" + String.Join(",", AllowedGroups) + ")" : "");
+ }
+ }
+}
\ No newline at end of file
diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/DB/RegionManager.cs
index e3fa0025..40e9b957 100644
--- a/TShockAPI/DB/RegionManager.cs
+++ b/TShockAPI/DB/RegionManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -38,22 +38,23 @@ namespace TShockAPI.DB
{
database = db;
var table = new SqlTable("Regions",
- new SqlColumn("X1", MySqlDbType.Int32),
- new SqlColumn("Y1", MySqlDbType.Int32),
- new SqlColumn("width", MySqlDbType.Int32),
- new SqlColumn("height", MySqlDbType.Int32),
- new SqlColumn("RegionName", MySqlDbType.VarChar, 50) {Primary = true},
- new SqlColumn("WorldID", MySqlDbType.Text),
- new SqlColumn("UserIds", MySqlDbType.Text),
- new SqlColumn("Protected", MySqlDbType.Int32),
- new SqlColumn("Groups", MySqlDbType.Text),
- new SqlColumn("Owner", MySqlDbType.VarChar, 50),
- new SqlColumn("Z", MySqlDbType.Int32){ DefaultValue = "0" }
+ new SqlColumn("Id", MySqlDbType.Int32) {Primary = true, AutoIncrement = true},
+ new SqlColumn("X1", MySqlDbType.Int32),
+ new SqlColumn("Y1", MySqlDbType.Int32),
+ new SqlColumn("width", MySqlDbType.Int32),
+ new SqlColumn("height", MySqlDbType.Int32),
+ new SqlColumn("RegionName", MySqlDbType.VarChar, 50) {Unique = true},
+ new SqlColumn("WorldID", MySqlDbType.VarChar, 50) { Unique = true },
+ new SqlColumn("UserIds", MySqlDbType.Text),
+ new SqlColumn("Protected", MySqlDbType.Int32),
+ new SqlColumn("Groups", MySqlDbType.Text),
+ new SqlColumn("Owner", MySqlDbType.VarChar, 50),
+ new SqlColumn("Z", MySqlDbType.Int32){ DefaultValue = "0" }
);
var creator = new SqlTableCreator(db,
- db.GetSqlType() == SqlType.Sqlite
- ? (IQueryBuilder) new SqliteQueryCreator()
- : new MysqlQueryCreator());
+ db.GetSqlType() == SqlType.Sqlite
+ ? (IQueryBuilder) new SqliteQueryCreator()
+ : new MysqlQueryCreator());
creator.EnsureExists(table);
}
@@ -78,7 +79,7 @@ namespace TShockAPI.DB
string name = reader.Get("RegionName");
string owner = reader.Get("Owner");
string groups = reader.Get("Groups");
- int z = reader.Get("Z");
+ int z = reader.Get("Z");
string[] splitids = mergedids.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
@@ -114,53 +115,6 @@ namespace TShockAPI.DB
}
}
- public void ReloadForUnitTest(String n)
- {
- using (var reader = database.QueryReader("SELECT * FROM Regions WHERE WorldID=@0", n))
- {
- Regions.Clear();
- while (reader.Read())
- {
- int X1 = reader.Get("X1");
- int Y1 = reader.Get("Y1");
- int height = reader.Get("height");
- int width = reader.Get("width");
- int Protected = reader.Get("Protected");
- string MergedIDs = reader.Get("UserIds");
- string name = reader.Get("RegionName");
- string[] SplitIDs = MergedIDs.Split(',');
- string owner = reader.Get("Owner");
- string groups = reader.Get("Groups");
- int z = reader.Get("Z");
-
- Region r = new Region(new Rectangle(X1, Y1, width, height), name, owner, Protected != 0, Main.worldID.ToString(), z);
- r.SetAllowedGroups(groups);
- try
- {
- for (int i = 0; i < SplitIDs.Length; i++)
- {
- int id;
-
- if (Int32.TryParse(SplitIDs[i], out id)) // if unparsable, it's not an int, so silently skip
- r.AllowedIDs.Add(id);
- else if (SplitIDs[i] == "") // Split gotcha, can return an empty string with certain conditions
- // but we only want to let the user know if it's really a nonparsable integer.
- Log.Warn("UnitTest: One of your UserIDs is not a usable integer: " + SplitIDs[i]);
- }
- }
- catch (Exception e)
- {
- Log.Error("Your database contains invalid UserIDs (they should be ints).");
- Log.Error("A lot of things will fail because of this. You must manually delete and re-create the allowed field.");
- Log.Error(e.Message);
- Log.Error(e.StackTrace);
- }
-
- Regions.Add(r);
- }
- }
- }
-
public bool AddRegion(int tx, int ty, int width, int height, string regionname, string owner, string worldid, int z = 0)
{
if (GetRegionByName(regionname) != null)
@@ -203,7 +157,7 @@ namespace TShockAPI.DB
try
{
database.Query("UPDATE Regions SET Protected=@0 WHERE RegionName=@1 AND WorldID=@2", state ? 1 : 0, name,
- Main.worldID.ToString());
+ Main.worldID.ToString());
var region = GetRegionByName(name);
if (region != null)
region.DisableBuild = state;
@@ -239,26 +193,26 @@ namespace TShockAPI.DB
{
return false;
}
- Region top = null;
+ Region top = null;
- foreach (Region region in Regions.ToList())
- {
- if (region.InArea(x, y))
- {
- if (top == null || region.Z > top.Z)
- top = region;
- }
- }
- return top == null || top.HasPermissionToBuildInRegion(ply);
+ foreach (Region region in Regions.ToList())
+ {
+ if (region.InArea(x, y))
+ {
+ if (top == null || region.Z > top.Z)
+ top = region;
+ }
+ }
+ return top == null || top.HasPermissionToBuildInRegion(ply);
}
public bool InArea(int x, int y)
{
- foreach (Region region in Regions.ToList())
+ foreach (Region region in Regions.ToList())
{
if (x >= region.Area.Left && x <= region.Area.Right &&
- y >= region.Area.Top && y <= region.Area.Bottom &&
- region.DisableBuild)
+ y >= region.Area.Top && y <= region.Area.Bottom &&
+ region.DisableBuild)
{
return true;
}
@@ -266,35 +220,35 @@ namespace TShockAPI.DB
return false;
}
- public List InAreaRegionName(int x, int y)
- {
- List regions = new List() { };
- foreach (Region region in Regions.ToList())
- {
- if (x >= region.Area.Left && x <= region.Area.Right &&
- y >= region.Area.Top && y <= region.Area.Bottom &&
- region.DisableBuild)
- {
- regions.Add(region.Name);
- }
- }
- return regions;
- }
+ public List InAreaRegionName(int x, int y)
+ {
+ List regions = new List() { };
+ foreach (Region region in Regions.ToList())
+ {
+ if (x >= region.Area.Left && x <= region.Area.Right &&
+ y >= region.Area.Top && y <= region.Area.Bottom &&
+ region.DisableBuild)
+ {
+ regions.Add(region.Name);
+ }
+ }
+ return regions;
+ }
- public List InAreaRegion(int x, int y)
- {
- List regions = new List() { };
- foreach (Region region in Regions.ToList())
- {
- if (x >= region.Area.Left && x <= region.Area.Right &&
- y >= region.Area.Top && y <= region.Area.Bottom &&
- region.DisableBuild)
- {
- regions.Add(region);
- }
- }
- return regions;
- }
+ public List InAreaRegion(int x, int y)
+ {
+ List regions = new List() { };
+ foreach (Region region in Regions.ToList())
+ {
+ if (x >= region.Area.Left && x <= region.Area.Right &&
+ y >= region.Area.Top && y <= region.Area.Bottom &&
+ region.DisableBuild)
+ {
+ regions.Add(region);
+ }
+ }
+ return regions;
+ }
public static List ListIDs(string MergedIDs)
{
@@ -311,52 +265,43 @@ namespace TShockAPI.DB
int Y = 0;
int height = 0;
int width = 0;
+
try
{
- using (
- var reader = database.QueryReader("SELECT X1, Y1, height, width FROM Regions WHERE RegionName=@0 AND WorldID=@1",
- regionName, Main.worldID.ToString()))
+ using (var reader = database.QueryReader("SELECT X1, Y1, height, width FROM Regions WHERE RegionName=@0 AND WorldID=@1",
+ regionName, Main.worldID.ToString()))
{
if (reader.Read())
+ {
X = reader.Get("X1");
- width = reader.Get("width");
- Y = reader.Get("Y1");
- height = reader.Get("height");
- }
- if (!(direction == 0))
- {
- if (!(direction == 1))
- {
- if (!(direction == 2))
- {
- if (!(direction == 3))
- {
- return false;
- }
- else
- {
- X -= addAmount;
- width += addAmount;
- }
- }
- else
- {
- height += addAmount;
- }
+ width = reader.Get("width");
+ Y = reader.Get("Y1");
+ height = reader.Get("height");
}
- else
- {
+ }
+ switch (direction)
+ {
+ case 0:
+ Y -= addAmount;
+ height += addAmount;
+ break;
+ case 1:
width += addAmount;
- }
+ break;
+ case 2:
+ height += addAmount;
+ break;
+ case 3:
+ X -= addAmount;
+ width += addAmount;
+ break;
+ default:
+ return false;
}
- else
- {
- Y -= addAmount;
- height += addAmount;
- }
- int q =
- database.Query(
- "UPDATE Regions SET X1 = @0, Y1 = @1, width = @2, height = @3 WHERE RegionName = @4 AND WorldID=@5", X, Y, width,
+
+ foreach (var region in Regions.Where(r => r.Name == regionName))
+ region.Area = new Rectangle(X, Y, width, height);
+ int q = database.Query("UPDATE Regions SET X1 = @0, Y1 = @1, width = @2, height = @3 WHERE RegionName = @4 AND WorldID=@5", X, Y, width,
height, regionName, Main.worldID.ToString());
if (q > 0)
return true;
@@ -376,7 +321,7 @@ namespace TShockAPI.DB
r.RemoveID(TShock.Users.GetUserID(userName));
string ids = string.Join(",", r.AllowedIDs);
int q = database.Query("UPDATE Regions SET UserIds=@0 WHERE RegionName=@1 AND WorldID=@2", ids,
- regionName, Main.worldID.ToString());
+ regionName, Main.worldID.ToString());
if (q > 0)
return true;
}
@@ -390,7 +335,7 @@ namespace TShockAPI.DB
string mergedIDs = string.Empty;
using (
var reader = database.QueryReader("SELECT UserIds FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName,
- Main.worldID.ToString()))
+ Main.worldID.ToString()))
{
if (reader.Read())
mergedIDs = reader.Get("UserIds");
@@ -408,7 +353,7 @@ namespace TShockAPI.DB
mergedIDs = string.Concat(mergedIDs, ",", userIdToAdd);
int q = database.Query("UPDATE Regions SET UserIds=@0 WHERE RegionName=@1 AND WorldID=@2", mergedIDs,
- regionName, Main.worldID.ToString());
+ regionName, Main.worldID.ToString());
foreach (var r in Regions)
{
if (r.Name == regionName && r.WorldID == Main.worldID.ToString())
@@ -478,16 +423,6 @@ namespace TShockAPI.DB
return Regions.FirstOrDefault(r => r.Name.Equals(name) && r.WorldID == Main.worldID.ToString());
}
- public Region ZacksGetRegionByName(String name)
- {
- foreach (Region r in Regions)
- {
- if (r.Name.Equals(name))
- return r;
- }
- return null;
- }
-
public bool ChangeOwner(string regionName, string newOwner)
{
var region = GetRegionByName(regionName);
@@ -495,7 +430,7 @@ namespace TShockAPI.DB
{
region.Owner = newOwner;
int q = database.Query("UPDATE Regions SET Owner=@0 WHERE RegionName=@1 AND WorldID=@2", newOwner,
- regionName, Main.worldID.ToString());
+ regionName, Main.worldID.ToString());
if (q > 0)
return true;
}
@@ -507,7 +442,7 @@ namespace TShockAPI.DB
string mergedGroups = "";
using (
var reader = database.QueryReader("SELECT Groups FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName,
- Main.worldID.ToString()))
+ Main.worldID.ToString()))
{
if (reader.Read())
mergedGroups = reader.Get("Groups");
@@ -523,7 +458,7 @@ namespace TShockAPI.DB
mergedGroups += groupName;
int q = database.Query("UPDATE Regions SET Groups=@0 WHERE RegionName=@1 AND WorldID=@2", mergedGroups,
- regionName, Main.worldID.ToString());
+ regionName, Main.worldID.ToString());
Region r = GetRegionByName(regionName);
if (r != null)
@@ -546,47 +481,47 @@ namespace TShockAPI.DB
r.RemoveGroup(group);
string groups = string.Join(",", r.AllowedGroups);
int q = database.Query("UPDATE Regions SET Groups=@0 WHERE RegionName=@1 AND WorldID=@2", groups,
- regionName, Main.worldID.ToString());
+ regionName, Main.worldID.ToString());
if (q > 0)
return true;
}
return false;
}
- public Region GetTopRegion( List regions )
- {
- Region ret = null;
- foreach( Region r in regions)
- {
- if (ret == null)
- ret = r;
- else
- {
- if (r.Z > ret.Z)
- ret = r;
- }
- }
- return ret;
- }
+ public Region GetTopRegion( List regions )
+ {
+ Region ret = null;
+ foreach( Region r in regions)
+ {
+ if (ret == null)
+ ret = r;
+ else
+ {
+ if (r.Z > ret.Z)
+ ret = r;
+ }
+ }
+ return ret;
+ }
- public bool SetZ( string name, int z )
- {
- try
- {
- database.Query("UPDATE Regions SET Z=@0 WHERE RegionName=@1 AND WorldID=@2", z, name,
- Main.worldID.ToString());
+ public bool SetZ( string name, int z )
+ {
+ try
+ {
+ database.Query("UPDATE Regions SET Z=@0 WHERE RegionName=@1 AND WorldID=@2", z, name,
+ Main.worldID.ToString());
- var region = GetRegionByName(name);
- if (region != null)
- region.Z = z;
- return true;
- }
- catch (Exception ex)
- {
- Log.Error(ex.ToString());
- return false;
- }
- }
+ var region = GetRegionByName(name);
+ if (region != null)
+ region.Z = z;
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ return false;
+ }
+ }
}
public class Region
@@ -598,7 +533,7 @@ namespace TShockAPI.DB
public string WorldID { get; set; }
public List AllowedIDs { get; set; }
public List AllowedGroups { get; set; }
- public int Z { get; set; }
+ public int Z { get; set; }
public Region(Rectangle region, string name, string owner, bool disablebuild, string RegionWorldIDz, int z)
: this()
@@ -608,7 +543,7 @@ namespace TShockAPI.DB
Owner = owner;
DisableBuild = disablebuild;
WorldID = RegionWorldIDz;
- Z = z;
+ Z = z;
}
public Region()
@@ -619,7 +554,7 @@ namespace TShockAPI.DB
WorldID = string.Empty;
AllowedIDs = new List();
AllowedGroups = new List();
- Z = 0;
+ Z = 0;
}
public bool InArea(Rectangle point)
diff --git a/TShockAPI/DB/RememberedPosManager.cs b/TShockAPI/DB/RememberedPosManager.cs
index 604743ff..ad2d62e2 100644
--- a/TShockAPI/DB/RememberedPosManager.cs
+++ b/TShockAPI/DB/RememberedPosManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/DB/SqlColumn.cs b/TShockAPI/DB/SqlColumn.cs
index 9b59c89e..8fd72d88 100644
--- a/TShockAPI/DB/SqlColumn.cs
+++ b/TShockAPI/DB/SqlColumn.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/DB/SqlTable.cs b/TShockAPI/DB/SqlTable.cs
index 08275ef9..7fb62ed9 100644
--- a/TShockAPI/DB/SqlTable.cs
+++ b/TShockAPI/DB/SqlTable.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/DB/SqlValue.cs b/TShockAPI/DB/SqlValue.cs
index 04161e90..9edb13e0 100644
--- a/TShockAPI/DB/SqlValue.cs
+++ b/TShockAPI/DB/SqlValue.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/DB/TileManager.cs b/TShockAPI/DB/TileManager.cs
new file mode 100644
index 00000000..9362e664
--- /dev/null
+++ b/TShockAPI/DB/TileManager.cs
@@ -0,0 +1,253 @@
+/*
+TShock, a server mod for Terraria
+Copyright (C) 2011-2015 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 .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using MySql.Data.MySqlClient;
+
+namespace TShockAPI.DB
+{
+ public class TileManager
+ {
+ private IDbConnection database;
+ public List TileBans = new List();
+
+ public TileManager(IDbConnection db)
+ {
+ database = db;
+
+ var table = new SqlTable("TileBans",
+ new SqlColumn("TileId", MySqlDbType.Int32) { Primary = true },
+ new SqlColumn("AllowedGroups", MySqlDbType.Text)
+ );
+ var creator = new SqlTableCreator(db,
+ db.GetSqlType() == SqlType.Sqlite
+ ? (IQueryBuilder)new SqliteQueryCreator()
+ : new MysqlQueryCreator());
+ creator.EnsureExists(table);
+ UpdateBans();
+ }
+
+ public void UpdateBans()
+ {
+ TileBans.Clear();
+
+ using (var reader = database.QueryReader("SELECT * FROM TileBans"))
+ {
+ while (reader != null && reader.Read())
+ {
+ TileBan ban = new TileBan((short)reader.Get("TileId"));
+ ban.SetAllowedGroups(reader.Get("AllowedGroups"));
+ TileBans.Add(ban);
+ }
+ }
+ }
+
+ public void AddNewBan(short id = 0)
+ {
+ try
+ {
+ database.Query("INSERT INTO TileBans (TileId, AllowedGroups) VALUES (@0, @1);",
+ id, "");
+
+ if (!TileIsBanned(id, null))
+ TileBans.Add(new TileBan(id));
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+
+ public void RemoveBan(short id)
+ {
+ if (!TileIsBanned(id, null))
+ return;
+ try
+ {
+ database.Query("DELETE FROM TileBans WHERE TileId=@0;", id);
+ TileBans.Remove(new TileBan(id));
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+
+ public bool TileIsBanned(short id)
+ {
+ if (TileBans.Contains(new TileBan(id)))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public bool TileIsBanned(short id, TSPlayer ply)
+ {
+ if (TileBans.Contains(new TileBan(id)))
+ {
+ TileBan b = GetBanById(id);
+ return !b.HasPermissionToPlaceTile(ply);
+ }
+ return false;
+ }
+
+ public bool AllowGroup(short id, string name)
+ {
+ string groupsNew = "";
+ TileBan b = GetBanById(id);
+ if (b != null)
+ {
+ try
+ {
+ groupsNew = String.Join(",", b.AllowedGroups);
+ if (groupsNew.Length > 0)
+ groupsNew += ",";
+ groupsNew += name;
+ b.SetAllowedGroups(groupsNew);
+
+ int q = database.Query("UPDATE TileBans SET AllowedGroups=@0 WHERE TileId=@1", groupsNew,
+ id);
+
+ return q > 0;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+
+ return false;
+ }
+
+ public bool RemoveGroup(short id, string group)
+ {
+ TileBan b = GetBanById(id);
+ if (b != null)
+ {
+ try
+ {
+ b.RemoveGroup(group);
+ string groups = string.Join(",", b.AllowedGroups);
+ int q = database.Query("UPDATE TileBans SET AllowedGroups=@0 WHERE TileId=@1", groups,
+ id);
+
+ if (q > 0)
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+ return false;
+ }
+
+ public TileBan GetBanById(short id)
+ {
+ foreach (TileBan b in TileBans)
+ {
+ if (b.ID == id)
+ {
+ return b;
+ }
+ }
+ return null;
+ }
+ }
+
+ public class TileBan : IEquatable
+ {
+ public short ID { get; set; }
+ public List AllowedGroups { get; set; }
+
+ public TileBan(short id)
+ : this()
+ {
+ ID = id;
+ AllowedGroups = new List();
+ }
+
+ public TileBan()
+ {
+ ID = 0;
+ AllowedGroups = new List();
+ }
+
+ public bool Equals(TileBan other)
+ {
+ return ID == other.ID;
+ }
+
+ public bool HasPermissionToPlaceTile(TSPlayer ply)
+ {
+ if (ply == null)
+ return false;
+
+ if (ply.Group.HasPermission(Permissions.canusebannedtiles))
+ return true;
+
+ var cur = ply.Group;
+ var traversed = new List();
+ while (cur != null)
+ {
+ if (AllowedGroups.Contains(cur.Name))
+ {
+ return true;
+ }
+ if (traversed.Contains(cur))
+ {
+ throw new InvalidOperationException("Infinite group parenting ({0})".SFormat(cur.Name));
+ }
+ traversed.Add(cur);
+ cur = cur.Parent;
+ }
+ return false;
+ // could add in the other permissions in this class instead of a giant if switch.
+ }
+
+ public void SetAllowedGroups(String groups)
+ {
+ // prevent null pointer exceptions
+ if (!string.IsNullOrEmpty(groups))
+ {
+ List groupArr = groups.Split(',').ToList();
+
+ for (int i = 0; i < groupArr.Count; i++)
+ {
+ groupArr[i] = groupArr[i].Trim();
+ //Console.WriteLine(groupArr[i]);
+ }
+ AllowedGroups = groupArr;
+ }
+ }
+
+ public bool RemoveGroup(string groupName)
+ {
+ return AllowedGroups.Remove(groupName);
+ }
+
+ public override string ToString()
+ {
+ return ID + (AllowedGroups.Count > 0 ? " (" + String.Join(",", AllowedGroups) + ")" : "");
+ }
+ }
+}
\ No newline at end of file
diff --git a/TShockAPI/DB/UserManager.cs b/TShockAPI/DB/UserManager.cs
index 37267b79..07b94f63 100644
--- a/TShockAPI/DB/UserManager.cs
+++ b/TShockAPI/DB/UserManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/DB/WarpsManager.cs b/TShockAPI/DB/WarpsManager.cs
index ef47890c..fc4890af 100644
--- a/TShockAPI/DB/WarpsManager.cs
+++ b/TShockAPI/DB/WarpsManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -40,10 +40,11 @@ namespace TShockAPI.DB
database = db;
var table = new SqlTable("Warps",
- new SqlColumn("WarpName", MySqlDbType.VarChar, 50) {Primary = true},
+ new SqlColumn("Id", MySqlDbType.Int32){Primary = true, AutoIncrement = true},
+ new SqlColumn("WarpName", MySqlDbType.VarChar, 50) {Unique = true},
new SqlColumn("X", MySqlDbType.Int32),
new SqlColumn("Y", MySqlDbType.Int32),
- new SqlColumn("WorldID", MySqlDbType.Text),
+ new SqlColumn("WorldID", MySqlDbType.VarChar, 50) { Unique = true },
new SqlColumn("Private", MySqlDbType.Text)
);
var creator = new SqlTableCreator(db,
diff --git a/TShockAPI/Extensions/DbExt.cs b/TShockAPI/Extensions/DbExt.cs
index 3f1db5c7..5dd6e0e6 100644
--- a/TShockAPI/Extensions/DbExt.cs
+++ b/TShockAPI/Extensions/DbExt.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -118,22 +118,42 @@ namespace TShockAPI.DB
typeof (bool),
(s, i) => s.GetBoolean(i)
},
+ {
+ typeof (bool?),
+ (s, i) => s.IsDBNull(i) ? null : (object)s.GetBoolean(i)
+ },
{
typeof (byte),
(s, i) => s.GetByte(i)
},
+ {
+ typeof (byte?),
+ (s, i) => s.IsDBNull(i) ? null : (object)s.GetByte(i)
+ },
{
typeof (Int16),
(s, i) => s.GetInt16(i)
},
+ {
+ typeof (Int16?),
+ (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt16(i)
+ },
{
typeof (Int32),
(s, i) => s.GetInt32(i)
},
+ {
+ typeof (Int32?),
+ (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt32(i)
+ },
{
typeof (Int64),
(s, i) => s.GetInt64(i)
},
+ {
+ typeof (Int64?),
+ (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt64(i)
+ },
{
typeof (string),
(s, i) => s.GetString(i)
@@ -142,14 +162,26 @@ namespace TShockAPI.DB
typeof (decimal),
(s, i) => s.GetDecimal(i)
},
+ {
+ typeof (decimal?),
+ (s, i) => s.IsDBNull(i) ? null : (object)s.GetDecimal(i)
+ },
{
typeof (float),
(s, i) => s.GetFloat(i)
},
+ {
+ typeof (float?),
+ (s, i) => s.IsDBNull(i) ? null : (object)s.GetFloat(i)
+ },
{
typeof (double),
(s, i) => s.GetDouble(i)
},
+ {
+ typeof (double?),
+ (s, i) => s.IsDBNull(i) ? null : (object)s.GetDouble(i)
+ },
{
typeof (object),
(s, i) => s.GetValue(i)
diff --git a/TShockAPI/Extensions/LinqExt.cs b/TShockAPI/Extensions/LinqExt.cs
index 86b639bd..e1885bbd 100644
--- a/TShockAPI/Extensions/LinqExt.cs
+++ b/TShockAPI/Extensions/LinqExt.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Extensions/RandomExt.cs b/TShockAPI/Extensions/RandomExt.cs
index e0a866bf..42abce9a 100644
--- a/TShockAPI/Extensions/RandomExt.cs
+++ b/TShockAPI/Extensions/RandomExt.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Extensions/StringExt.cs b/TShockAPI/Extensions/StringExt.cs
index ea67e801..fe6dcfa2 100644
--- a/TShockAPI/Extensions/StringExt.cs
+++ b/TShockAPI/Extensions/StringExt.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs
index 581fe393..071da3fc 100644
--- a/TShockAPI/FileTools.cs
+++ b/TShockAPI/FileTools.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -18,6 +18,7 @@ along with this program. If not, see .
using System;
using System.IO;
+using TShockAPI.ServerSideCharacters;
namespace TShockAPI
{
@@ -55,6 +56,14 @@ namespace TShockAPI
get { return Path.Combine(TShock.SavePath, "config.json"); }
}
+ ///
+ /// Path to the file containing the config.
+ ///
+ internal static string ServerSideCharacterConfigPath
+ {
+ get { return Path.Combine(TShock.SavePath, "sscconfig.json"); }
+ }
+
///
/// Creates an empty file at the given path.
///
@@ -98,6 +107,12 @@ namespace TShockAPI
}
TShock.Config.Write(ConfigPath);
+ if (File.Exists(ServerSideCharacterConfigPath))
+ {
+ TShock.ServerSideCharacterConfig = ServerSideConfig.Read(ServerSideCharacterConfigPath);
+ // Add all the missing config properties in the json file
+ }
+ TShock.ServerSideCharacterConfig.Write(ServerSideCharacterConfigPath);
}
///
diff --git a/TShockAPI/GeoIPCountry.cs b/TShockAPI/GeoIPCountry.cs
index 4ca30777..764a69a2 100644
--- a/TShockAPI/GeoIPCountry.cs
+++ b/TShockAPI/GeoIPCountry.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index 57ffe22a..2680ac10 100755
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -25,6 +25,7 @@ using System.IO.Streams;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Terraria.ID;
using TShockAPI.DB;
using TShockAPI.Net;
using Terraria;
@@ -79,7 +80,7 @@ namespace TShockAPI
///
/// The Tile ID being edited.
///
- public byte EditData { get; set; }
+ public short EditData { get; set; }
///
/// The EditType.
/// (KillTile = 0, PlaceTile = 1, KillWall = 2, PlaceWall = 3, KillTileNoItem = 4, PlaceWire = 5, KillWire = 6)
@@ -101,7 +102,7 @@ namespace TShockAPI
/// TileEdit - called when a tile is placed or destroyed
///
public static HandlerList TileEdit;
- private static bool OnTileEdit(TSPlayer ply, int x, int y, EditAction action, EditType editDetail, byte editData, byte style)
+ private static bool OnTileEdit(TSPlayer ply, int x, int y, EditAction action, EditType editDetail, short editData, byte style)
{
if (TileEdit == null)
return false;
@@ -1023,7 +1024,7 @@ namespace TShockAPI
///
/// ???
///
- public byte ID { get; set; }
+ public short ID { get; set; }
///
/// Direction the damage occurred from
///
@@ -1033,9 +1034,9 @@ namespace TShockAPI
///
public short Damage { get; set; }
///
- /// Is PVP enabled...?
+ /// Knockback
///
- public byte PVP { get; set; }
+ public float Knockback { get; set; }
///
/// Critical?
///
@@ -1046,7 +1047,7 @@ namespace TShockAPI
///
public static HandlerList NPCStrike;
- private static bool OnNPCStrike(byte id, byte dir, short dmg, byte pvp, byte crit)
+ private static bool OnNPCStrike(short id, byte dir, short dmg, float knockback, byte crit)
{
if (NPCStrike == null)
return false;
@@ -1056,7 +1057,7 @@ namespace TShockAPI
ID = id,
Direction = dir,
Damage = dmg,
- PVP = pvp,
+ Knockback = knockback,
Critical = crit,
};
NPCStrike.Invoke(null, args);
@@ -1198,7 +1199,7 @@ namespace TShockAPI
{
#region Blacklists
- WhitelistBuffMaxTime = new int[Main.maxBuffs];
+ WhitelistBuffMaxTime = new int[Main.maxBuffTypes];
WhitelistBuffMaxTime[20] = 600;
WhitelistBuffMaxTime[0x18] = 1200;
WhitelistBuffMaxTime[0x1f] = 120;
@@ -1207,43 +1208,46 @@ namespace TShockAPI
#endregion Blacklists
GetDataHandlerDelegates = new Dictionary
- {
- {PacketTypes.PlayerInfo, HandlePlayerInfo},
- {PacketTypes.PlayerUpdate, HandlePlayerUpdate},
- {PacketTypes.Tile, HandleTile},
- {PacketTypes.TileSendSquare, HandleSendTileSquare},
- {PacketTypes.ProjectileNew, HandleProjectileNew},
- {PacketTypes.TogglePvp, HandleTogglePvp},
- {PacketTypes.PlayerTeam, HandlePlayerTeam},
- {PacketTypes.TileKill, HandleTileKill},
- {PacketTypes.PlayerKillMe, HandlePlayerKillMe},
- {PacketTypes.LiquidSet, HandleLiquidSet},
- {PacketTypes.PlayerSpawn, HandleSpawn},
- {PacketTypes.ChestGetContents, HandleChestOpen},
- {PacketTypes.ChestOpen, HandleChestActive},
- {PacketTypes.ChestItem, HandleChestItem},
- {PacketTypes.SignNew, HandleSign},
- {PacketTypes.PlayerSlot, HandlePlayerSlot},
- {PacketTypes.TileGetSection, HandleGetSection},
- {PacketTypes.UpdateNPCHome, UpdateNPCHome},
- {PacketTypes.PlayerAddBuff, HandlePlayerBuff},
- {PacketTypes.ItemDrop, HandleItemDrop},
- {PacketTypes.PlayerHp, HandlePlayerHp},
- {PacketTypes.PlayerMana, HandlePlayerMana},
- {PacketTypes.PlayerDamage, HandlePlayerDamage},
- {PacketTypes.NpcStrike, HandleNpcStrike},
- {PacketTypes.NpcSpecial, HandleSpecial},
- {PacketTypes.PlayerAnimation, HandlePlayerAnimation},
- {PacketTypes.PlayerBuff, HandlePlayerBuffUpdate},
- {PacketTypes.PasswordSend, HandlePassword},
- {PacketTypes.ContinueConnecting2, HandleConnecting},
- {PacketTypes.ProjectileDestroy, HandleProjectileKill},
- {PacketTypes.SpawnBossorInvasion, HandleSpawnBoss},
- {PacketTypes.Teleport, HandleTeleport},
- {PacketTypes.PaintTile, HandlePaintTile},
- {PacketTypes.PaintWall, HandlePaintWall},
- {PacketTypes.Placeholder, HandleRaptor}
- };
+ {
+ { PacketTypes.PlayerInfo, HandlePlayerInfo },
+ { PacketTypes.PlayerUpdate, HandlePlayerUpdate },
+ { PacketTypes.Tile, HandleTile },
+ { PacketTypes.TileSendSquare, HandleSendTileSquare },
+ { PacketTypes.ProjectileNew, HandleProjectileNew },
+ { PacketTypes.TogglePvp, HandleTogglePvp },
+ { PacketTypes.PlayerTeam, HandlePlayerTeam },
+ { PacketTypes.TileKill, HandleTileKill },
+ { PacketTypes.PlayerKillMe, HandlePlayerKillMe },
+ { PacketTypes.LiquidSet, HandleLiquidSet },
+ { PacketTypes.PlayerSpawn, HandleSpawn },
+ { PacketTypes.ChestGetContents, HandleChestOpen },
+ { PacketTypes.ChestOpen, HandleChestActive },
+ { PacketTypes.ChestItem, HandleChestItem },
+ { PacketTypes.SignNew, HandleSign },
+ { PacketTypes.PlayerSlot, HandlePlayerSlot },
+ { PacketTypes.TileGetSection, HandleGetSection },
+ { PacketTypes.UpdateNPCHome, UpdateNPCHome },
+ { PacketTypes.PlayerAddBuff, HandlePlayerAddBuff },
+ { PacketTypes.ItemDrop, HandleItemDrop },
+ { PacketTypes.ItemOwner, HandleItemOwner },
+ { PacketTypes.PlayerHp, HandlePlayerHp },
+ { PacketTypes.PlayerMana, HandlePlayerMana },
+ { PacketTypes.PlayerDamage, HandlePlayerDamage },
+ { PacketTypes.NpcStrike, HandleNpcStrike },
+ { PacketTypes.NpcSpecial, HandleSpecial },
+ { PacketTypes.PlayerAnimation, HandlePlayerAnimation },
+ { PacketTypes.PlayerBuff, HandlePlayerBuffList },
+ { PacketTypes.PasswordSend, HandlePassword },
+ { PacketTypes.ContinueConnecting2, HandleConnecting },
+ { PacketTypes.ProjectileDestroy, HandleProjectileKill },
+ { PacketTypes.SpawnBossorInvasion, HandleSpawnBoss },
+ { PacketTypes.Teleport, HandleTeleport },
+ { PacketTypes.PaintTile, HandlePaintTile },
+ { PacketTypes.PaintWall, HandlePaintWall },
+ { PacketTypes.DoorUse, HandleDoorUse },
+ { PacketTypes.CompleteAnglerQuest, HandleCompleteAnglerQuest },
+ { PacketTypes.NumberOfAnglerQuestsCompleted, HandleNumberOfAnglerQuestsCompleted }
+ };
}
public static bool HandlerGetData(PacketTypes type, TSPlayer player, MemoryStream data)
@@ -1280,19 +1284,9 @@ namespace TShockAPI
bypassTrashCanCheck = true;
}
- if (OnPlayerSlot(plr, slot, stack, prefix, type))
+ if (OnPlayerSlot(plr, slot, stack, prefix, type) || plr != args.Player.Index || slot < 0 || slot > NetItem.maxNetInventory || args.Player.IgnoreSSCPackets)
return true;
- if (plr != args.Player.Index)
- {
- return true;
- }
-
- if (slot < 0 || slot > NetItem.maxNetInventory)
- {
- return true;
- }
-
// Garabage? Or will it cause some internal initialization or whatever?
var item = new Item();
item.netDefaults(type);
@@ -1302,14 +1296,19 @@ namespace TShockAPI
{
args.Player.PlayerData.StoreSlot(slot, type, prefix, stack);
}
- else if (
- TShock.Config.ServerSideCharacter && TShock.Config.DisableLoginBeforeJoin && !bypassTrashCanCheck &&
- args.Player.HasSentInventory && !args.Player.Group.HasPermission(Permissions.bypassinventorychecks)
- ) {
+ else if (Main.ServerSideCharacter && TShock.Config.DisableLoginBeforeJoin && !bypassTrashCanCheck &&
+ args.Player.HasSentInventory && !args.Player.Group.HasPermission(Permissions.bypassssc))
+ {
// The player might have moved an item to their trash can before they performed a single login attempt yet.
args.Player.IgnoreActionsForClearingTrashCan = true;
}
+ if (slot == 58) //this is the hand
+ {
+ item.stack = stack;
+ args.Player.ItemInHand = item;
+ }
+
return false;
}
@@ -1319,15 +1318,12 @@ namespace TShockAPI
var cur = args.Data.ReadInt16();
var max = args.Data.ReadInt16();
- if (OnPlayerHP(plr, cur, max) || cur <= 0)
+ if (OnPlayerHP(plr, cur, max) || cur <= 0 || max <= 0 || args.Player.IgnoreSSCPackets)
return true;
- if (args.Player.FirstMaxHP == 0)
- args.Player.FirstMaxHP = max;
-
- if (cur < 0 || cur > 500 || max < 100 || max > 500) //Abnormal values have the potential to cause infinite loops in the server.
+ if (max > TShock.Config.MaxHP && !args.Player.Group.HasPermission(Permissions.ignorehp))
{
- TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true);
+ args.Player.Disable("Maximum HP beyond limit");
return true;
}
@@ -1340,9 +1336,8 @@ namespace TShockAPI
if (args.Player.GodMode && (cur < max))
{
- args.Player.Heal(args.TPlayer.statLifeMax);
+ args.Player.Heal(args.TPlayer.statLifeMax2);
}
-
return false;
}
@@ -1352,16 +1347,13 @@ namespace TShockAPI
var cur = args.Data.ReadInt16();
var max = args.Data.ReadInt16();
- if (OnPlayerMana(plr, cur, max))
+ if (OnPlayerMana(plr, cur, max) || cur < 0 || max < 0 || args.Player.IgnoreSSCPackets)
return true;
- if (args.Player.FirstMaxMP == 0)
- args.Player.FirstMaxMP = max;
-
- if (cur < 0 || cur > 400 || max < 0 || max > 200) //Abnormal values have the potential to cause infinite loops in the server.
+ if (max > TShock.Config.MaxMP && !args.Player.Group.HasPermission(Permissions.ignoremp))
{
- TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true);
- return false;
+ args.Player.Disable("Maximum MP beyond limit");
+ return true;
}
if (args.Player.IsLoggedIn)
@@ -1370,18 +1362,25 @@ namespace TShockAPI
args.Player.TPlayer.statManaMax = max;
args.Player.PlayerData.maxMana = max;
}
-
return false;
}
private static bool HandlePlayerInfo(GetDataHandlerArgs args)
{
var playerid = args.Data.ReadInt8();
+ var male = args.Data.ReadByte() == 0;
var hair = args.Data.ReadInt8();
- var male = args.Data.ReadBoolean();
- args.Data.Position += 21;
+ string name = args.Data.ReadString();
+ byte hairDye = args.Data.ReadInt8();
+ BitsByte hideVisual = 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());
var difficulty = args.Data.ReadInt8();
- string name = Encoding.UTF8.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1)));
if (OnPlayerInfo(playerid, hair, male, difficulty, name))
{
@@ -1396,6 +1395,16 @@ namespace TShockAPI
}
if (args.Player.ReceivedInfo)
{
+ // Since Terraria 1.2.3 these character properties can change ingame.
+ args.Player.TPlayer.hair = hair;
+ args.Player.TPlayer.hairColor = hairColor;
+ args.Player.TPlayer.hairDye = hairDye;
+ args.Player.TPlayer.pantsColor = pantsColor;
+ args.Player.TPlayer.shirtColor = shirtColor;
+ args.Player.TPlayer.underShirtColor = underShirtColor;
+ args.Player.TPlayer.shoeColor = shoeColor;
+ args.Player.TPlayer.hideVisual = hideVisual;
+ NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, args.Player.Index, args.Player.Name, args.Player.Index);
return true;
}
if (TShock.Config.MediumcoreOnly && difficulty < 1)
@@ -1431,9 +1440,9 @@ namespace TShockAPI
var group = TShock.Utils.GetGroup(user.Group);
- if (TShock.Config.ServerSideCharacter)
+ if (Main.ServerSideCharacter)
{
- if (group.HasPermission(Permissions.bypassinventorychecks))
+ if (group.HasPermission(Permissions.bypassssc))
{
args.Player.IgnoreActionsForClearingTrashCan = false;
}
@@ -1454,7 +1463,7 @@ namespace TShockAPI
args.Player.IsLoggedIn = true;
args.Player.IgnoreActionsForInventory = "none";
- if (!args.Player.IgnoreActionsForClearingTrashCan && TShock.Config.ServerSideCharacter)
+ if (!args.Player.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter)
{
args.Player.PlayerData.CopyCharacter(args.Player);
TShock.CharacterDB.InsertPlayerData(args.Player);
@@ -1489,7 +1498,7 @@ namespace TShockAPI
if (!args.Player.RequiresPassword)
return true;
- string password = Encoding.UTF8.GetString(args.Data.ReadBytes((int) (args.Data.Length - args.Data.Position - 1)));
+ string password = args.Data.ReadString();
if (Hooks.PlayerHooks.OnPlayerPreLogin(args.Player, args.Player.Name, password))
return true;
@@ -1509,9 +1518,9 @@ namespace TShockAPI
var group = TShock.Utils.GetGroup(user.Group);
- if (TShock.Config.ServerSideCharacter)
+ if (Main.ServerSideCharacter)
{
- if (group.HasPermission(Permissions.bypassinventorychecks))
+ if (group.HasPermission(Permissions.bypassssc))
{
args.Player.IgnoreActionsForClearingTrashCan = false;
}
@@ -1532,7 +1541,7 @@ namespace TShockAPI
args.Player.IsLoggedIn = true;
args.Player.IgnoreActionsForInventory = "none";
- if (!args.Player.IgnoreActionsForClearingTrashCan && TShock.Config.ServerSideCharacter)
+ if (!args.Player.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter)
{
args.Player.PlayerData.CopyCharacter(args.Player);
TShock.CharacterDB.InsertPlayerData(args.Player);
@@ -1594,7 +1603,7 @@ namespace TShockAPI
///
/// Tiles that can be oriented (e.g., beds, chairs, bathtubs, etc).
///
- private static byte[] orientableTiles = new byte[] { 15, 79, 90, 105, 128, 137, 139, 171, 207, 209 };
+ private static int[] orientableTiles = new int[] { TileID.Cannon, 15, 79, 90, 105, TileID.Mannequin, 137, 139, 171, 207, 314, TileID.Womannequin, TileID.MinecartTrack, TileID.WeaponsRack };
private static bool HandleSendTileSquare(GetDataHandlerArgs args)
{
@@ -1602,8 +1611,8 @@ namespace TShockAPI
return false;
var size = args.Data.ReadInt16();
- var tileX = args.Data.ReadInt32();
- var tileY = args.Data.ReadInt32();
+ var tileX = args.Data.ReadInt16();
+ var tileY = args.Data.ReadInt16();
if (OnSendTileSquare(size, tileX, tileY))
return true;
@@ -1662,9 +1671,8 @@ namespace TShockAPI
Main.tile[realx, realy].frameY = newtile.FrameY;
changed = true;
}
-
// Landmine
- if (tile.type == 210 && !newtile.Active)
+ if (tile.type == TileID.LandMine && !newtile.Active)
{
Main.tile[realx, realy].active(false);
changed = true;
@@ -1707,7 +1715,7 @@ namespace TShockAPI
if (changed)
{
- TSPlayer.All.SendTileSquare(tileX, tileY, size);
+ TSPlayer.All.SendTileSquare(tileX, tileY, size + 1);
WorldGen.RangeFrame(tileX, tileY, tileX + size, tileY + size);
}
else
@@ -1748,9 +1756,25 @@ namespace TShockAPI
}
///
- /// Tiles that can be broken without any tools.
+ /// Tiles that can be broken without any pickaxes/etc.
///
- private static byte[] breakableTiles = new byte[] { 4, 13, 33, 49, 50, 127, 128, 162 };
+ private static int[] breakableTiles = new int[]
+ {
+ TileID.Books,
+ TileID.Bottles,
+ TileID.BreakableIce,
+ TileID.Candles,
+ TileID.CorruptGrass,
+ TileID.Dirt,
+ TileID.FleshGrass,
+ TileID.Grass,
+ TileID.HallowedGrass,
+ TileID.MagicalIceBlock,
+ TileID.Mannequin,
+ TileID.Torches,
+ TileID.WaterCandle,
+ TileID.Womannequin,
+ };
///
/// The maximum place styles for each tile.
///
@@ -1758,17 +1782,28 @@ namespace TShockAPI
///
/// These projectiles create tiles on death.
///
- private static Dictionary projectileCreatesTile = new Dictionary {{42, 53}, {65, 112}, {68, 116}};
+ private static Dictionary projectileCreatesTile = new Dictionary
+ {
+ { 17, TileID.Dirt },
+ { 42, TileID.Sand },
+ { 65, TileID.Ebonsand },
+ { 68, TileID.Pearlsand },
+ { 354, TileID.Crimsand },
+ };
+ ///
+ /// Extra place style limits for strange hardcoded values in Terraria
+ ///
+ private static Dictionary ExtraneousPlaceStyles = new Dictionary{{TileID.MinecartTrack, 3}};
private static bool HandleTile(GetDataHandlerArgs args)
{
EditAction action = (EditAction)args.Data.ReadInt8();
- var tileX = args.Data.ReadInt32();
- var tileY = args.Data.ReadInt32();
+ var tileX = args.Data.ReadInt16();
+ var tileY = args.Data.ReadInt16();
try
{
- var editData = args.Data.ReadInt8();
+ var editData = args.Data.ReadInt16();
EditType type = (action == EditAction.KillTile || action == EditAction.KillWall ||
action == EditAction.KillTileNoItem)
? EditType.Fail
@@ -1780,7 +1815,11 @@ namespace TShockAPI
if (OnTileEdit(args.Player, tileX, tileY, action, type, editData, style))
return true;
- if (!TShock.Utils.TilePlacementValid(tileX, tileY) || (args.Player.Dead && TShock.Config.PreventDeadModification))
+ if (!TShock.Utils.TilePlacementValid(tileX, tileY))
+ return true;
+ if (action == EditAction.KillTile && Main.tile[tileX, tileY].type == TileID.MagicalIceBlock)
+ return false;
+ if (args.Player.Dead && TShock.Config.PreventDeadModification)
return true;
if (args.Player.AwaitingName)
@@ -1858,6 +1897,17 @@ namespace TShockAPI
Item selectedItem = args.Player.SelectedItem;
int lastKilledProj = args.Player.LastKilledProjectile;
Tile tile = Main.tile[tileX, tileY];
+
+ if (action == EditAction.PlaceTile)
+ {
+ if (TShock.TileBans.TileIsBanned(editData, args.Player))
+ {
+ args.Player.SendTileSquare(tileX, tileY, 1);
+ args.Player.SendErrorMessage("You do not have permission to place this tile.");
+ return true;
+ }
+ }
+
if (action == EditAction.KillTile && !Main.tileCut[tile.type] && !breakableTiles.Contains(tile.type))
{
// If the tile is an axe tile and they aren't selecting an axe, they're hacking.
@@ -1894,8 +1944,9 @@ namespace TShockAPI
}
else if (action == EditAction.PlaceTile || action == EditAction.PlaceWall)
{
- if (action == EditAction.PlaceTile && TShock.Config.PreventInvalidPlaceStyle &&
- MaxPlaceStyles.ContainsKey(editData) && style > MaxPlaceStyles[editData])
+ if ((action == EditAction.PlaceTile && TShock.Config.PreventInvalidPlaceStyle) &&
+ (MaxPlaceStyles.ContainsKey(editData) && style > MaxPlaceStyles[editData]) &&
+ (ExtraneousPlaceStyles.ContainsKey(editData) && style > ExtraneousPlaceStyles[editData]))
{
args.Player.SendTileSquare(tileX, tileY, 4);
return true;
@@ -1912,7 +1963,7 @@ namespace TShockAPI
args.Player.SendTileSquare(tileX, tileY, 4);
return true;
}
- if (action == EditAction.PlaceTile && (editData == 29 || editData == 97) && TShock.Config.ServerSideCharacter)
+ if (action == EditAction.PlaceTile && (editData == 29 || editData == 97) && Main.ServerSideCharacter)
{
args.Player.SendErrorMessage("You cannot place this tile because server side characters are enabled.");
args.Player.SendTileSquare(tileX, tileY, 3);
@@ -1979,14 +2030,8 @@ namespace TShockAPI
return true;
}
- // Ignore ice rod break
- if ((editData == 127 || Main.tileCut[editData]) && (action == EditAction.KillTile || action == EditAction.KillTileNoItem))
- {
- return false;
- }
-
// Ignore rope placement range
- if ((editData != 213 || action != EditAction.PlaceTile) && TShock.CheckRangePermission(args.Player, tileX, tileY))
+ if ((editData != TileID.Rope || action != EditAction.PlaceTile) && TShock.CheckRangePermission(args.Player, tileX, tileY))
{
args.Player.SendTileSquare(tileX, tileY, 4);
return true;
@@ -2158,11 +2203,14 @@ namespace TShockAPI
private static bool HandlePlayerUpdate(GetDataHandlerArgs args)
{
var plr = args.Data.ReadInt8();
- var control = args.Data.ReadInt8();
+ var control = (BitsByte)args.Data.ReadInt8();
+ var pulley = (BitsByte)args.Data.ReadInt8();
var item = args.Data.ReadInt8();
var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
- var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
- byte pulley = args.Data.ReadInt8();
+ var vel = Vector2.Zero;
+ if(pulley[2])
+ vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
+
if (OnPlayerUpdate(plr, control, item, pos, vel, pulley))
return true;
@@ -2245,11 +2293,11 @@ namespace TShockAPI
args.Player.LastNetPosition = pos;
}
- if ((control & 32) == 32)
+ if (control[5])
{
if (TShock.Itembans.ItemIsBanned(args.TPlayer.inventory[item].name, args.Player))
{
- control -= 32;
+ control[5] = false;
args.Player.Disable("Using banned item");
args.Player.SendMessage(
string.Format("You cannot use {0} on this server. Your actions are being ignored.",
@@ -2278,8 +2326,8 @@ namespace TShockAPI
args.TPlayer.selectedItem = item;
args.TPlayer.position = pos;
- args.TPlayer.velocity = vel;
args.TPlayer.oldVelocity = args.TPlayer.velocity;
+ args.TPlayer.velocity = vel;
args.TPlayer.fallStart = (int) (pos.Y/16f);
args.TPlayer.controlUp = false;
args.TPlayer.controlDown = false;
@@ -2287,41 +2335,45 @@ namespace TShockAPI
args.TPlayer.controlRight = false;
args.TPlayer.controlJump = false;
args.TPlayer.controlUseItem = false;
- args.TPlayer.pulley = pulley != 0;
- args.TPlayer.pulleyDir = pulley;
+ args.TPlayer.pulley = pulley[0];
+ if(pulley[0])
+ args.TPlayer.pulleyDir = (byte)(pulley[1] ? 2 : 1);
args.TPlayer.direction = -1;
- if ((control & 1) == 1)
+ if (control[0])
{
args.TPlayer.controlUp = true;
}
- if ((control & 2) == 2)
+ if (control[1])
{
args.TPlayer.controlDown = true;
}
- if ((control & 4) == 4)
+ if (control[2])
{
args.TPlayer.controlLeft = true;
}
- if ((control & 8) == 8)
+ if (control[3])
{
args.TPlayer.controlRight = true;
}
- if ((control & 16) == 16)
+ if (control[4])
{
args.TPlayer.controlJump = true;
}
- if ((control & 32) == 32)
+ if (control[5])
{
args.TPlayer.controlUseItem = true;
}
- if ((control & 64) == 64)
+ if (control[6])
{
args.TPlayer.direction = 1;
}
-
+ else
+ {
+ args.TPlayer.direction = -1;
+ }
- if (args.Player.Confused && TShock.Config.ServerSideCharacter && args.Player.IsLoggedIn)
+ if (args.Player.Confused && Main.ServerSideCharacter && args.Player.IsLoggedIn)
{
if (args.TPlayer.controlUp)
{
@@ -2366,7 +2418,19 @@ namespace TShockAPI
var dmg = args.Data.ReadInt16();
var owner = args.Data.ReadInt8();
var type = args.Data.ReadInt16();
+ var bits = (BitsByte) args.Data.ReadInt8();
owner = (byte)args.Player.Index;
+ float[] ai = new float[Projectile.maxAI];
+
+ for (int i = 0; i < Projectile.maxAI; i++)
+ {
+ if (bits[i])
+ ai[i] = args.Data.ReadSingle();
+ else
+ ai[i] = 0f;
+ }
+
+
var index = TShock.Utils.SearchProjectile(ident, owner);
if (OnNewProjectile(ident, pos, vel, knockback, dmg, owner, type, index))
@@ -2374,9 +2438,17 @@ namespace TShockAPI
if (index > Main.maxProjectiles || index < 0)
{
- return false;
+ args.Player.RemoveProjectile(ident, owner);
+ return true;
}
+ if (TShock.ProjectileBans.ProjectileIsBanned(type, args.Player))
+ {
+ args.Player.Disable("Player does not have permission to create that projectile.", true);
+ args.Player.SendErrorMessage("You do not have permission to create that projectile.");
+ args.Player.RemoveProjectile(ident, owner);
+ return true;
+ }
// Server now checks owner + ident, if owner is different, server will create new projectile.
/*if (args.Player.Index != owner)
{
@@ -2428,13 +2500,13 @@ namespace TShockAPI
if (!args.Player.Group.HasPermission(Permissions.ignoreprojectiledetection))
{
- if ((type == 90) && (TShock.Config.ProjIgnoreShrapnel))// ignore shrapnel
+ if (type == 90 && TShock.Config.ProjIgnoreShrapnel) // Ignore crystal shards
{
Log.Debug("Ignoring shrapnel per config..");
}
- else
+ else if (!Main.projectile[index].active)
{
- args.Player.ProjectileThreshold++;
+ args.Player.ProjectileThreshold++; // Creating new projectile
}
}
@@ -2500,13 +2572,14 @@ namespace TShockAPI
private static bool HandlePlayerKillMe(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt8();
- var direction = args.Data.ReadInt8();
+ var direction = (byte)(args.Data.ReadInt8() - 1);
var dmg = args.Data.ReadInt16();
var pvp = args.Data.ReadInt8() == 0;
-
+ var text = args.Data.ReadString();
if (dmg > 20000) //Abnormal values have the potential to cause infinite loops in the server.
{
TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true);
+ Log.ConsoleError("Death Exploit Attempt: Damage {0}", dmg);
return false;
}
@@ -2518,23 +2591,39 @@ namespace TShockAPI
if (OnKillMe(id, direction, dmg, pvp))
return true;
- int textlength = (int)(args.Data.Length - args.Data.Position - 1);
- string deathtext = "";
- if (textlength > 0)
- {
- deathtext = Encoding.UTF8.GetString(args.Data.ReadBytes(textlength));
- }
-
- if (deathtext.Length > 500)
+ if (text.Length > 500)
{
TShock.Utils.Kick(TShock.Players[id], "Crash attempt", true);
return true;
}
- args.Player.LastDeath = DateTime.Now;
args.Player.Dead = true;
+ args.Player.RespawnTimer = TShock.Config.RespawnSeconds;
- if (args.TPlayer.difficulty == 2 && TShock.Config.ServerSideCharacter && args.Player.IsLoggedIn)
+ foreach (NPC npc in Main.npc)
+ {
+ if (npc.active && (npc.boss || npc.type == 13 || npc.type == 14 || npc.type == 15) &&
+ Math.Abs(args.TPlayer.center().X - npc.center().X) + Math.Abs(args.TPlayer.center().Y - npc.center().Y) < 4000f)
+ {
+ args.Player.RespawnTimer = TShock.Config.RespawnBossSeconds;
+ break;
+ }
+ }
+
+ if (args.TPlayer.difficulty == 2 && (TShock.Config.KickOnHardcoreDeath || TShock.Config.BanOnHardcoreDeath))
+ {
+ if (TShock.Config.BanOnHardcoreDeath)
+ {
+ if (!TShock.Utils.Ban(args.Player, TShock.Config.HardcoreBanReason, false, "hardcore-death"))
+ TShock.Utils.ForceKick(args.Player, "Death results in a ban, but can't ban you.", true);
+ }
+ else
+ {
+ TShock.Utils.ForceKick(args.Player, TShock.Config.HardcoreKickReason, true, false);
+ }
+ }
+
+ if (args.TPlayer.difficulty == 2 && Main.ServerSideCharacter && args.Player.IsLoggedIn)
{
User user = TShock.Users.GetUserByName(args.Player.UserAccountName);
if (TShock.CharacterDB.RemovePlayer(user.ID))
@@ -2548,8 +2637,8 @@ namespace TShockAPI
private static bool HandleLiquidSet(GetDataHandlerArgs args)
{
- int tileX = args.Data.ReadInt32();
- int tileY = args.Data.ReadInt32();
+ int tileX = args.Data.ReadInt16();
+ int tileY = args.Data.ReadInt16();
byte amount = args.Data.ReadInt8();
byte type = args.Data.ReadInt8();
@@ -2668,8 +2757,11 @@ namespace TShockAPI
private static bool HandleTileKill(GetDataHandlerArgs args)
{
- var tileX = args.Data.ReadInt32();
- var tileY = args.Data.ReadInt32();
+ int flag = args.Data.ReadByte();
+ int tileX = args.Data.ReadInt16();
+ int tileY = args.Data.ReadInt16();
+ int style = args.Data.ReadInt16();
+
if (OnTileKill(tileX, tileY))
return true;
if (!TShock.Utils.TilePlacementValid(tileX, tileY) || (args.Player.Dead && TShock.Config.PreventDeadModification))
@@ -2681,7 +2773,7 @@ namespace TShockAPI
return true;
}
- if (Main.tile[tileX, tileY].type != 0x15 && (!TShock.Utils.MaxChests() && Main.tile[tileX, tileY].type != 0)) //Chest
+ if (flag != 0 && Main.tile[tileX, tileY].type != 21 && (!TShock.Utils.MaxChests() && Main.tile[tileX, tileY].type != 0)) //Chest
{
args.Player.SendTileSquare(tileX, tileY, 3);
return true;
@@ -2698,15 +2790,14 @@ namespace TShockAPI
args.Player.SendTileSquare(tileX, tileY, 3);
return true;
}
-
return false;
}
private static bool HandleSpawn(GetDataHandlerArgs args)
{
var player = args.Data.ReadInt8();
- var spawnx = args.Data.ReadInt32();
- var spawny = args.Data.ReadInt32();
+ var spawnx = args.Data.ReadInt16();
+ var spawny = args.Data.ReadInt16();
if (OnPlayerSpawn(player, spawnx, spawny))
return true;
@@ -2733,7 +2824,7 @@ namespace TShockAPI
else
args.Player.InitSpawn = true;
- if ((TShock.Config.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0) && (args.TPlayer.SpawnX > 0) && ((args.TPlayer.SpawnX != args.Player.sX) && (args.TPlayer.SpawnY != args.Player.sY)))
+ if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0) && (args.TPlayer.SpawnX > 0) && ((args.TPlayer.SpawnX != args.Player.sX) && (args.TPlayer.SpawnY != args.Player.sY)))
{
args.Player.sX=args.TPlayer.SpawnX;
@@ -2743,7 +2834,7 @@ namespace TShockAPI
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) -48);
}
- else if ((TShock.Config.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0))
+ else if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0))
{
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == 79)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY -1)))
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) -48);
@@ -2755,8 +2846,8 @@ namespace TShockAPI
private static bool HandleChestOpen(GetDataHandlerArgs args)
{
- var x = args.Data.ReadInt32();
- var y = args.Data.ReadInt32();
+ var x = args.Data.ReadInt16();
+ var y = args.Data.ReadInt16();
if (OnChestOpen(x, y, args.Player))
return true;
@@ -2782,8 +2873,13 @@ namespace TShockAPI
private static bool HandleChestActive(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt16();
- var x = args.Data.ReadInt32();
- var y = args.Data.ReadInt32();
+ var x = args.Data.ReadInt16();
+ var y = args.Data.ReadInt16();
+ var b = args.Data.ReadInt8();
+ var name = "";
+
+ if (b != 0 && b <= 20)
+ name = args.Data.ReadString();
args.Player.ActiveChest = id;
@@ -2841,8 +2937,9 @@ namespace TShockAPI
private static bool HandleSign(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt16();
- var x = args.Data.ReadInt32();
- var y = args.Data.ReadInt32();
+ var x = args.Data.ReadInt16();
+ var y = args.Data.ReadInt16();
+ var text = args.Data.ReadString();
if (OnSignEvent(id, x, y))
return true;
@@ -2897,7 +2994,7 @@ namespace TShockAPI
return false;
}
- private static bool HandlePlayerBuff(GetDataHandlerArgs args)
+ private static bool HandlePlayerAddBuff(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt8();
var type = args.Data.ReadInt8();
@@ -2908,28 +3005,29 @@ namespace TShockAPI
if (TShock.CheckIgnores(args.Player))
{
- args.Player.SendData(PacketTypes.PlayerBuff, "", id);
+ args.Player.SendData(PacketTypes.PlayerAddBuff, "", id);
return true;
}
if (id >= Main.maxPlayers)
{
+ args.Player.SendData(PacketTypes.PlayerAddBuff, "", id);
return true;
}
- if (!TShock.Players[id].TPlayer.hostile)
+ if (!TShock.Players[id].TPlayer.hostile || !Main.pvpBuff[type])
{
- args.Player.SendData(PacketTypes.PlayerBuff, "", id);
+ args.Player.SendData(PacketTypes.PlayerAddBuff, "", id);
return true;
}
if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 50))
{
- args.Player.SendData(PacketTypes.PlayerBuff, "", id);
+ args.Player.SendData(PacketTypes.PlayerAddBuff, "", id);
return true;
}
if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000)
{
- args.Player.SendData(PacketTypes.PlayerBuff, "", id);
+ args.Player.SendData(PacketTypes.PlayerAddBuff, "", id);
return true;
}
@@ -2938,7 +3036,7 @@ namespace TShockAPI
return false;
}
- args.Player.SendData(PacketTypes.PlayerBuff, "", id);
+ args.Player.SendData(PacketTypes.PlayerAddBuff, "", id);
return true;
}
@@ -2949,23 +3047,43 @@ namespace TShockAPI
var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
var stacks = args.Data.ReadInt16();
var prefix = args.Data.ReadInt8();
- var noDelay = args.Data.ReadBoolean();
+ var noDelay = args.Data.ReadInt8() == 1;
var type = args.Data.ReadInt16();
if (OnItemDrop(id, pos, vel, stacks, prefix, noDelay, type))
return true;
- // player is attempting to crash clients
+ // player is attempting to crash clients
if (type < -48 || type >= Main.maxItemTypes)
{
+ args.Player.SendData(PacketTypes.ItemDrop, "", id);
return true;
}
- if (type == 0) //Item removed, let client do this to prevent item duplication client side
+
+ if (prefix > Item.maxPrefixes) //make sure the prefix is a legit value
{
+ args.Player.SendData(PacketTypes.ItemDrop, "", id);
+ return true;
+ }
+
+ if (type == 0) //Item removed, let client do this to prevent item duplication client side (but only if it passed the range check)
+ {
+ if (TShock.CheckRangePermission(args.Player, (int)(Main.item[id].position.X / 16f), (int)(Main.item[id].position.Y / 16f)))
+ {
+ args.Player.SendData(PacketTypes.ItemDrop, "", id);
+ return true;
+ }
+
return false;
}
- if (TShock.CheckRangePermission(args.Player, (int) (pos.X/16f), (int) (pos.Y/16f)))
+ if (TShock.CheckRangePermission(args.Player, (int)(pos.X / 16f), (int)(pos.Y / 16f)))
+ {
+ args.Player.SendData(PacketTypes.ItemDrop, "", id);
+ return true;
+ }
+
+ if (Main.item[id].active && Main.item[id].netID != type) //stop the client from changing the item type of a drop but only if the client isn't picking up the item
{
args.Player.SendData(PacketTypes.ItemDrop, "", id);
return true;
@@ -2978,7 +3096,7 @@ namespace TShockAPI
args.Player.SendData(PacketTypes.ItemDrop, "", id);
return true;
}
- if ((TShock.Config.ServerSideCharacter) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.Config.LogonDiscardThreshold))
+ if ((Main.ServerSideCharacter) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.ServerSideCharacterConfig.LogonDiscardThreshold))
{
//Player is probably trying to sneak items onto the server in their hands!!!
Log.ConsoleInfo(string.Format("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.name));
@@ -2995,34 +3113,36 @@ namespace TShockAPI
return false;
}
+ private static bool HandleItemOwner(GetDataHandlerArgs args)
+ {
+ var id = args.Data.ReadInt16();
+ var owner = args.Data.ReadInt8();
+
+ if (id < 0 || id > 400)
+ return true;
+
+ if (id == 400 && owner == 255)
+ {
+ args.Player.IgnoreSSCPackets = false;
+ return true;
+ }
+
+ return false;
+ }
+
private static bool HandlePlayerDamage(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt8();
- var direction = args.Data.ReadInt8();
+ var direction = (byte)(args.Data.ReadInt8() - 1);
var dmg = args.Data.ReadInt16();
- var pvp = args.Data.ReadBoolean();
- var crit = args.Data.ReadBoolean();
-
- if (dmg > 12000) //Abnormal values have the potential to cause infinite loops in the server.
- { //12000 because Skely Prime Head does 10339 or some bs during the day.
- TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true);
- return false;
- }
+ var text = args.Data.ReadString();
+ var bits = (BitsByte)args.Data.ReadInt8();
+ var pvp = bits[0];
+ var crit = bits[1];
if (OnPlayerDamage(id, direction, dmg, pvp, crit))
return true;
- int textlength = (int) (args.Data.Length - args.Data.Position - 1);
- string deathtext = "";
- if (textlength > 0)
- {
- deathtext = Encoding.UTF8.GetString(args.Data.ReadBytes(textlength));
- /*if (!TShock.Utils.ValidString(deathtext))
- {
- return true;
- }*/
- }
-
if (id >= Main.maxPlayers || TShock.Players[id] == null)
{
return true;
@@ -3030,7 +3150,15 @@ namespace TShockAPI
if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index)
{
- args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage));
+ if (TShock.Config.KickOnDamageThresholdBroken)
+ {
+ TShock.Utils.Kick(args.Player, string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage));
+ return true;
+ }
+ else
+ {
+ args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage));
+ }
args.Player.SendData(PacketTypes.PlayerHp, "", id);
args.Player.SendData(PacketTypes.PlayerUpdate, "", id);
return true;
@@ -3074,13 +3202,13 @@ namespace TShockAPI
private static bool HandleNpcStrike(GetDataHandlerArgs args)
{
- var id = args.Data.ReadInt8();
- var direction = args.Data.ReadInt8();
+ var id = args.Data.ReadInt16();
var dmg = args.Data.ReadInt16();
- var pvp = args.Data.ReadInt8();
+ var knockback = args.Data.ReadSingle();
+ var direction = (byte)(args.Data.ReadInt8() - 1);
var crit = args.Data.ReadInt8();
- if (OnNPCStrike(id, direction, dmg, pvp, crit))
+ if (OnNPCStrike(id, direction, dmg, knockback, crit))
return true;
if (Main.npc[id] == null)
@@ -3088,7 +3216,15 @@ namespace TShockAPI
if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap))
{
- args.Player.Disable(String.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage ) );
+ if (TShock.Config.KickOnDamageThresholdBroken)
+ {
+ TShock.Utils.Kick(args.Player, string.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage));
+ return true;
+ }
+ else
+ {
+ args.Player.Disable(String.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage));
+ }
args.Player.SendData(PacketTypes.NpcUpdate, "", id);
return true;
}
@@ -3099,9 +3235,9 @@ namespace TShockAPI
return true;
}
- if (Main.npc[id].townNPC && !args.Player.Group.HasPermission(Permissions.movenpc))
+ if (Main.npc[id].townNPC && !args.Player.Group.HasPermission(Permissions.hurttownnpc))
{
- args.Player.SendMessage( "You don't have permission to move this NPC.", Color.Yellow);
+ args.Player.SendErrorMessage("You do not have permission to hurt this NPC.");
args.Player.SendData(PacketTypes.NpcUpdate, "", id);
return true;
}
@@ -3161,24 +3297,29 @@ namespace TShockAPI
return false;
}
- private static bool HandlePlayerBuffUpdate(GetDataHandlerArgs args)
+ private static bool HandlePlayerBuffList(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt8();
if (OnPlayerBuffUpdate(id))
return true;
- for (int i = 0; i < 10; i++)
+ for (int i = 0; i < Terraria.Player.maxBuffs; i++)
{
var buff = args.Data.ReadInt8();
- if (buff == 10)
+ /*if (TShock.Itembans.ItemBans.Any(s =>
{
- if (TShock.Itembans.ItemIsBanned("Invisibility Potion", args.Player))
- buff = 0;
- else if (TShock.Config.DisableInvisPvP && args.TPlayer.hostile)
- buff = 0;
- }
+ Item item = new Item();
+ item.SetDefaults(s.Name);
+ return item.buffType == buff;
+ }))
+ {
+ buff = 0;
+ }*/
+
+ if (buff == 10 && TShock.Config.DisableInvisPvP && args.TPlayer.hostile)
+ buff = 0;
args.TPlayer.buffType[i] = buff;
if (args.TPlayer.buffType[i] > 0)
@@ -3190,6 +3331,7 @@ namespace TShockAPI
args.TPlayer.buffTime[i] = 0;
}
}
+
NetMessage.SendData((int) PacketTypes.PlayerBuff, -1, args.Player.Index, "", args.Player.Index);
return true;
}
@@ -3233,6 +3375,7 @@ namespace TShockAPI
case 245:
case 262:
case 266:
+ case 370:
spawnboss = true;
break;
}
@@ -3257,13 +3400,13 @@ namespace TShockAPI
switch (Type)
{
case -5:
- boss = "a snow invasion";
+ boss = "a frost moon";
break;
case -4:
- boss = "a pumpkin invasion";
+ boss = "a pumpkin moon";
break;
case -3:
- boss = "the pirates";
+ boss = "the Pirates";
break;
case -2:
boss = "the Snow Legion";
@@ -3275,15 +3418,17 @@ namespace TShockAPI
boss = String.Format("the {0}", npc.name);
break;
}
-
- TShock.Utils.SendLogs(string.Format("{0} summoned {1}.", args.Player.Name, boss), Color.PaleVioletRed, args.Player);
+ if (TShock.Config.AnonymousBossInvasions)
+ TShock.Utils.SendLogs(string.Format("{0} summoned {1}!", args.Player.Name, boss), Color.PaleVioletRed, args.Player);
+ else
+ TShock.Utils.Broadcast(String.Format("{0} summoned {1}!", args.Player.Name, boss), 175, 75, 255);
return false;
}
private static bool HandlePaintTile(GetDataHandlerArgs args)
{
- var x = args.Data.ReadInt32();
- var y = args.Data.ReadInt32();
+ var x = args.Data.ReadInt16();
+ var y = args.Data.ReadInt16();
var t = args.Data.ReadInt8();
if (x < 0 || y < 0 || x >= Main.maxTilesX || y >= Main.maxTilesY || t > Main.numTileColors)
@@ -3296,8 +3441,13 @@ namespace TShockAPI
}
// Not selecting paintbrush or paint scraper or the spectre versions? Hacking.
- if (args.Player.SelectedItem.type != 1071 && args.Player.SelectedItem.type != 1100 &&
- args.Player.SelectedItem.type != 1543 && args.Player.SelectedItem.type != 1545)
+ if (args.Player.SelectedItem.type != ItemID.PaintRoller &&
+ args.Player.SelectedItem.type != ItemID.PaintScraper &&
+ args.Player.SelectedItem.type != ItemID.Paintbrush &&
+ args.Player.SelectedItem.type != ItemID.SpectrePaintRoller &&
+ args.Player.SelectedItem.type != ItemID.SpectrePaintScraper &&
+ args.Player.SelectedItem.type != ItemID.SpectrePaintbrush &&
+ !args.Player.Accessories.Any(i => i != null && i.stack > 0 && i.type == ItemID.PaintSprayer))
{
args.Player.SendData(PacketTypes.PaintTile, "", x, y, Main.tile[x, y].color());
return true;
@@ -3320,8 +3470,8 @@ namespace TShockAPI
private static bool HandlePaintWall(GetDataHandlerArgs args)
{
- var x = args.Data.ReadInt32();
- var y = args.Data.ReadInt32();
+ var x = args.Data.ReadInt16();
+ var y = args.Data.ReadInt16();
var t = args.Data.ReadInt8();
if (x < 0 || y < 0 || x >= Main.maxTilesX || y >= Main.maxTilesY || t > Main.numTileColors)
@@ -3334,8 +3484,13 @@ namespace TShockAPI
}
// Not selecting paint roller or paint scraper or the spectre versions? Hacking.
- if (args.Player.SelectedItem.type != 1072 && args.Player.SelectedItem.type != 1100 &&
- args.Player.SelectedItem.type != 1544 && args.Player.SelectedItem.type != 1545)
+ if (args.Player.SelectedItem.type != ItemID.PaintRoller &&
+ args.Player.SelectedItem.type != ItemID.PaintScraper &&
+ args.Player.SelectedItem.type != ItemID.Paintbrush &&
+ args.Player.SelectedItem.type != ItemID.SpectrePaintRoller &&
+ args.Player.SelectedItem.type != ItemID.SpectrePaintScraper &&
+ args.Player.SelectedItem.type != ItemID.SpectrePaintbrush &&
+ !args.Player.Accessories.Any(i => i != null && i.stack > 0 && i.type == ItemID.PaintSprayer))
{
args.Player.SendData(PacketTypes.PaintWall, "", x, y, Main.tile[x, y].wallColor());
return true;
@@ -3358,7 +3513,7 @@ namespace TShockAPI
private static bool HandleTeleport(GetDataHandlerArgs args)
{
- var flag = args.Data.ReadInt8();
+ var flag = (BitsByte)args.Data.ReadInt8();
var id = args.Data.ReadInt16();
var x = args.Data.ReadSingle();
var y = args.Data.ReadSingle();
@@ -3397,134 +3552,38 @@ namespace TShockAPI
args.Player.Teleport(args.TPlayer.position.X, args.TPlayer.position.Y);
return true;
}
-
- if (!isNPC)
- {
- TShock.Players[id].Teleport(x, y, style);
- }
}
- return true;
+ return false;
}
- private static bool HandleRaptor(GetDataHandlerArgs args)
+ private static bool HandleDoorUse(GetDataHandlerArgs args)
{
- var type = (RaptorPacketTypes)args.Data.ReadInt8();
+ var close = args.Data.ReadByte();
+ var x = args.Data.ReadInt16();
+ var y = args.Data.ReadInt16();
+ var dir = args.Data.ReadByte() == 0 ? -1 : 1;
- switch (type)
- {
- case RaptorPacketTypes.Acknowledge:
- args.Player.IsRaptor = true;
- // Send these if the player was logged in before this packet arrives
- if (args.Player.IsLoggedIn)
- {
- Task.Factory.StartNew(() =>
- {
- args.Player.SendRaptorPermissions();
- if (args.Player.Group.HasPermission(Permissions.manageregion))
- {
- for (int i = 0; i < TShock.Regions.Regions.Count; i++)
- args.Player.SendRaptorRegion(TShock.Regions.Regions[i]);
- }
- if (args.Player.Group.HasPermission(Permissions.managewarp))
- {
- for (int i = 0; i < TShock.Warps.Warps.Count; i++)
- args.Player.SendRaptorWarp(TShock.Warps.Warps[i]);
- }
- });
- }
- return true;
- case RaptorPacketTypes.Region:
- if (args.Player.Group.HasPermission(Permissions.manageregion))
- {
- int x = args.Data.ReadInt32();
- int y = args.Data.ReadInt32();
- int width = args.Data.ReadInt32();
- int height = args.Data.ReadInt32();
- string regionName = args.Data.ReadString();
+ if (x >= Main.maxTilesX || y >= Main.maxTilesY || x < 0 || y < 0) // Check for out of range
+ return true;
- Region region;
- if ((region = TShock.Regions.GetRegionByName(regionName)) == null)
- {
- TShock.Regions.AddRegion(x, y, width, height, regionName, args.Player.UserAccountName, Main.worldID.ToString());
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.manageregion) && tsplr != args.Player)
- tsplr.SendRaptorRegion(TShock.Regions.GetRegionByName(regionName));
- }
- Log.Info("{0} added region \"{1}\".", args.Player.UserAccountName, regionName);
- }
- else
- {
- TShock.Regions.PositionRegion(regionName, x, y, width, height);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.manageregion) && tsplr != args.Player)
- tsplr.SendRaptorRegion(region);
- }
- Log.Info("{0} moved region \"{1}\".", args.Player.UserAccountName, regionName);
- }
- }
- return true;
- case RaptorPacketTypes.RegionDelete:
- if (args.Player.Group.HasPermission(Permissions.manageregion))
- {
- string regionName = args.Data.ReadString();
- TShock.Regions.DeleteRegion(regionName);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.manageregion) && tsplr != args.Player)
- tsplr.SendRaptorRegionDeletion(regionName);
- }
- Log.Info("{0} deleted region \"{1}\".", args.Player.UserAccountName, regionName);
- }
- return true;
- case RaptorPacketTypes.Warp:
- if (args.Player.Group.HasPermission(Permissions.managewarp))
- {
- int x = args.Data.ReadInt32();
- int y = args.Data.ReadInt32();
- string warpName = args.Data.ReadString();
+ if (Main.tile[x, y].type != 10 && Main.tile[x, y].type != 11) // Check for tile types
+ return true;
- Warp warp = TShock.Warps.Find(warpName);
- if (warp == null)
- {
- TShock.Warps.Add(x, y, warpName);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.managewarp) && tsplr != args.Player)
- tsplr.SendRaptorWarp(TShock.Warps.Find(warpName));
- }
- Log.Info("{0} added warp \"{1}\".", args.Player.UserAccountName, warpName);
- }
- else
- {
- TShock.Warps.Position(warpName, x, y);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.managewarp) && tsplr != args.Player)
- tsplr.SendRaptorWarp(warp);
- }
- Log.Info("{0} moved warp \"{1}\".", args.Player.UserAccountName, warpName);
- }
- }
- return true;
- case RaptorPacketTypes.WarpDelete:
- if (args.Player.Group.HasPermission(Permissions.managewarp))
- {
- string warpName = args.Data.ReadString();
- TShock.Warps.Remove(warpName);
- foreach (TSPlayer tsplr in TShock.Players)
- {
- if (tsplr != null && tsplr.IsRaptor && tsplr.Group.HasPermission(Permissions.managewarp) && tsplr != args.Player)
- tsplr.SendRaptorWarpDeletion(warpName);
- }
- Log.Info("{0} deleted warp \"{1}\".", args.Player.UserAccountName, warpName);
- }
- return true;
- default:
- return true;
- }
+ return false;
+ }
+
+ private static bool HandleCompleteAnglerQuest(GetDataHandlerArgs args)
+ {
+ // Since packet 76 is NEVER sent to us, we actually have to rely on this to get the true count
+ args.TPlayer.anglerQuestsFinished++;
+ return false;
+ }
+
+ private static bool HandleNumberOfAnglerQuestsCompleted(GetDataHandlerArgs args)
+ {
+ // Never sent by vanilla client, ignore this
+ return true;
}
}
}
diff --git a/TShockAPI/Group.cs b/TShockAPI/Group.cs
index f90c56b9..7efcb07a 100644
--- a/TShockAPI/Group.cs
+++ b/TShockAPI/Group.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -235,12 +235,6 @@ namespace TShockAPI
negatedpermissions.Add(permission);
permissions.Remove(permission); // Ensure we don't have conflicting definitions for a permissions
}
-
- for (int i = 0; i < TShock.Players.Length; i++)
- {
- if (TShock.Players[i] != null && TShock.Players[i].IsRaptor)
- TShock.Players[i].SendRaptorPermissions();
- }
}
///
@@ -260,12 +254,6 @@ namespace TShockAPI
permissions.Add(permission);
negatedpermissions.Remove(permission); // Ensure we don't have conflicting definitions for a permissions
}
-
- for (int i = 0; i < TShock.Players.Length; i++)
- {
- if (TShock.Players[i] != null && TShock.Players[i].IsRaptor)
- TShock.Players[i].SendRaptorPermissions();
- }
}
///
@@ -293,11 +281,6 @@ namespace TShockAPI
return;
}
permissions.Remove(permission);
- for (int i = 0; i < TShock.Players.Length; i++)
- {
- if (TShock.Players[i] != null && TShock.Players[i].IsRaptor && TShock.Players[i].Group == this)
- TShock.Players[i].SendRaptorPermissions();
- }
}
///
diff --git a/TShockAPI/HandlerList.cs b/TShockAPI/HandlerList.cs
index 128e6c5e..07b9d548 100644
--- a/TShockAPI/HandlerList.cs
+++ b/TShockAPI/HandlerList.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Hooks/GeneralHooks.cs b/TShockAPI/Hooks/GeneralHooks.cs
index f84efabd..d07c4f4f 100644
--- a/TShockAPI/Hooks/GeneralHooks.cs
+++ b/TShockAPI/Hooks/GeneralHooks.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Hooks/PlayerHooks.cs b/TShockAPI/Hooks/PlayerHooks.cs
index 79db8a30..73e862a8 100644
--- a/TShockAPI/Hooks/PlayerHooks.cs
+++ b/TShockAPI/Hooks/PlayerHooks.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -43,8 +43,16 @@ namespace TShockAPI.Hooks
public string CommandName { get; set; }
public string CommandText { get; set; }
public List Parameters { get; set; }
+ public IEnumerable CommandList { get; set; }
}
+ public class PlayerChatEventArgs : HandledEventArgs
+ {
+ public TSPlayer Player { get; set; }
+ public string RawText { get; set; }
+ public string TShockFormattedText { get; set; }
+ }
+
public static class PlayerHooks
{
public delegate void PlayerPostLoginD(PlayerPostLoginEventArgs e);
@@ -56,6 +64,9 @@ namespace TShockAPI.Hooks
public delegate void PlayerCommandD(PlayerCommandEventArgs e);
public static event PlayerCommandD PlayerCommand;
+ public delegate void PlayerChatD(PlayerChatEventArgs e);
+ public static event PlayerChatD PlayerChat;
+
public static void OnPlayerPostLogin(TSPlayer ply)
{
if (PlayerPostLogin == null)
@@ -67,7 +78,7 @@ namespace TShockAPI.Hooks
PlayerPostLogin(args);
}
- public static bool OnPlayerCommand(TSPlayer player, string cmdName, string cmdText, List args)
+ public static bool OnPlayerCommand(TSPlayer player, string cmdName, string cmdText, List args, ref IEnumerable commands)
{
if (PlayerCommand == null)
{
@@ -78,10 +89,11 @@ namespace TShockAPI.Hooks
Player = player,
CommandName = cmdName,
CommandText = cmdText,
- Parameters = args
-
+ Parameters = args,
+ CommandList = commands
};
PlayerCommand(playerCommandEventArgs);
+ commands = playerCommandEventArgs.CommandList;
return playerCommandEventArgs.Handled;
}
@@ -94,5 +106,15 @@ namespace TShockAPI.Hooks
PlayerPreLogin(args);
return args.Handled;
}
+
+ public static void OnPlayerChat(TSPlayer ply, string rawtext, ref string tshockText)
+ {
+ if (PlayerChat == null)
+ return;
+
+ var args = new PlayerChatEventArgs {Player = ply, RawText = rawtext, TShockFormattedText = tshockText};
+ PlayerChat(args);
+ tshockText = args.TShockFormattedText;
+ }
}
}
diff --git a/TShockAPI/IPackable.cs b/TShockAPI/IPackable.cs
index b44bedc8..7dbb2d93 100644
--- a/TShockAPI/IPackable.cs
+++ b/TShockAPI/IPackable.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Log.cs b/TShockAPI/Log.cs
index 5af35747..b2bb540f 100644
--- a/TShockAPI/Log.cs
+++ b/TShockAPI/Log.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Net/BaseMsg.cs b/TShockAPI/Net/BaseMsg.cs
index 5db8814e..c6f3de54 100644
--- a/TShockAPI/Net/BaseMsg.cs
+++ b/TShockAPI/Net/BaseMsg.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -32,12 +32,12 @@ namespace TShockAPI.Net
public void PackFull(Stream stream)
{
long start = stream.Position;
- stream.WriteInt32(1);
+ stream.WriteInt16(0);
stream.WriteInt8((byte) ID);
Pack(stream);
long end = stream.Position;
stream.Position = start;
- stream.WriteInt32((int) (end - start) - 4);
+ stream.WriteInt16((short)end);
stream.Position = end;
}
diff --git a/TShockAPI/Net/DisconnectMsg.cs b/TShockAPI/Net/DisconnectMsg.cs
index eaaa6df8..9e5789b4 100644
--- a/TShockAPI/Net/DisconnectMsg.cs
+++ b/TShockAPI/Net/DisconnectMsg.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -33,7 +33,7 @@ namespace TShockAPI.Net
public override void Pack(Stream stream)
{
- stream.WriteBytes(Encoding.UTF8.GetBytes(Reason));
+ stream.WriteString(Reason);
}
}
}
\ No newline at end of file
diff --git a/TShockAPI/Net/NetTile.cs b/TShockAPI/Net/NetTile.cs
index 06cd4a28..c3ee7d6f 100644
--- a/TShockAPI/Net/NetTile.cs
+++ b/TShockAPI/Net/NetTile.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -26,7 +26,7 @@ namespace TShockAPI.Net
public class NetTile : IPackable
{
public bool Active { get; set; }
- public byte Type { get; set; }
+ public ushort Type { get; set; }
public short FrameX { get; set; }
public short FrameY { get; set; }
public bool Lighted { get; set; }
@@ -45,6 +45,7 @@ namespace TShockAPI.Net
public byte WallColor { get; set; }
public bool Slope { get; set; }
public bool Slope2 { get; set; }
+ public bool Slope3 { get; set; }
public bool HasColor
{
@@ -100,58 +101,58 @@ namespace TShockAPI.Net
public void Pack(Stream stream)
{
- var flags = TileFlags.None;
+ var bits = new BitsByte();
if ((Active) && (!Inactive))
- flags |= TileFlags.Active;
-
- if (Lighted)
- flags |= TileFlags.Lighted;
+ bits[0] = true;
if (HasWall)
- flags |= TileFlags.Wall;
+ bits[2] = true;
if (HasLiquid)
- flags |= TileFlags.Liquid;
+ bits[3] = true;
if (Wire)
- flags |= TileFlags.Wire;
+ bits[4] = true;
if (IsHalf)
- flags |= TileFlags.HalfBrick;
+ bits[5] = true;
if (IsActuator)
- flags |= TileFlags.Actuator;
+ bits[6] = true;
if (Inactive)
{
- flags |= TileFlags.Inactive;
+ bits[7] = true;
}
- stream.WriteInt8((byte) flags);
+ stream.WriteInt8((byte) bits);
- var flags2 = TileFlags2.None;
+ bits = new BitsByte();
if ((Wire2))
- flags2 |= TileFlags2.Wire2;
+ bits[0] = true;
if (Wire3)
- flags2 |= TileFlags2.Wire3;
+ bits[1] = true;
if (HasColor)
- flags2 |= TileFlags2.Color;
+ bits[2] = true;
if (HasWallColor)
- flags2 |= TileFlags2.WallColor;
+ bits[3] = true;
if (Slope)
- flags2 |= TileFlags2.Slope;
+ bits[4] = true;
if (Slope2)
- flags2 |= TileFlags2.Slope2;
+ bits[5] = true;
+
+ if (Slope3)
+ bits[6] = true;
- stream.WriteInt8((byte)flags2);
+ stream.WriteInt8((byte)bits);
if (HasColor)
{
@@ -165,7 +166,7 @@ namespace TShockAPI.Net
if (Active)
{
- stream.WriteInt8(Type);
+ stream.WriteInt16((short)Type);
if (FrameImportant)
{
stream.WriteInt16(FrameX);
@@ -185,28 +186,29 @@ namespace TShockAPI.Net
public void Unpack(Stream stream)
{
- var flags = (TileFlags) stream.ReadInt8();
- var flags2 = (TileFlags2)stream.ReadInt8();
+ var flags = (BitsByte) stream.ReadInt8();
+ var flags2 = (BitsByte)stream.ReadInt8();
- Wire2 = flags2.HasFlag(TileFlags2.Wire2);
- Wire3 = flags2.HasFlag(TileFlags2.Wire3);
- Slope = flags2.HasFlag(TileFlags2.Slope);
- Slope2 = flags2.HasFlag(TileFlags2.Slope2);
+ Wire2 = flags2[0];
+ Wire3 = flags2[1];
+ Slope = flags2[4];
+ Slope2 = flags2[5];
+ Slope3 = flags2[6];
- if (flags2.HasFlag(TileFlags2.Color))
+ if (flags2[2])
{
TileColor = stream.ReadInt8();
}
- if (flags2.HasFlag(TileFlags2.WallColor))
+ if (flags2[3])
{
WallColor = stream.ReadInt8();
}
- Active = flags.HasFlag(TileFlags.Active);
+ Active = flags[0];
if (Active)
{
- Type = stream.ReadInt8();
+ Type = stream.ReadUInt16();
if (FrameImportant)
{
FrameX = stream.ReadInt16();
@@ -214,62 +216,31 @@ namespace TShockAPI.Net
}
}
- if (flags.HasFlag(TileFlags.Lighted))
- {
- Lighted = true;
- }
-
- if (flags.HasFlag(TileFlags.Wall))
+ if (flags[2])
{
Wall = stream.ReadInt8();
}
- if (flags.HasFlag(TileFlags.Liquid))
+ if (flags[3])
{
Liquid = stream.ReadInt8();
LiquidType = stream.ReadInt8();
}
- if (flags.HasFlag(TileFlags.Wire))
+ if (flags[4])
Wire = true;
- if (flags.HasFlag(TileFlags.HalfBrick))
+ if (flags[5])
IsHalf = true;
- if (flags.HasFlag(TileFlags.Actuator))
+ if (flags[6])
IsActuator = true;
- if (flags.HasFlag(TileFlags.Inactive))
+ if (flags[7])
{
Inactive = true;
Active = false;
}
}
}
-
- [Flags]
- public enum TileFlags : byte
- {
- None = 0,
- Active = 1,
- Lighted = 2,
- Wall = 4,
- Liquid = 8,
- Wire = 16,
- HalfBrick = 32,
- Actuator = 64,
- Inactive = 128
- }
-
- [Flags]
- public enum TileFlags2 : byte
- {
- None = 0,
- Wire2 = 1,
- Wire3 = 2,
- Color = 4,
- WallColor = 8,
- Slope = 16,
- Slope2 = 32
- }
}
diff --git a/TShockAPI/Net/ProjectileRemoveMsg.cs b/TShockAPI/Net/ProjectileRemoveMsg.cs
index 1f7907e6..a576e5bd 100644
--- a/TShockAPI/Net/ProjectileRemoveMsg.cs
+++ b/TShockAPI/Net/ProjectileRemoveMsg.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -41,8 +41,7 @@ namespace TShockAPI.Net
stream.WriteSingle(0);
stream.WriteInt16(0);
stream.WriteByte(Owner);
- stream.WriteByte(0);
- stream.WriteSingle(0);
+ stream.WriteInt16(0);
stream.WriteSingle(0);
stream.WriteSingle(0);
}
diff --git a/TShockAPI/Net/SpawnMsg.cs b/TShockAPI/Net/SpawnMsg.cs
index 849e5627..2fa15e59 100644
--- a/TShockAPI/Net/SpawnMsg.cs
+++ b/TShockAPI/Net/SpawnMsg.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -28,8 +28,8 @@ namespace TShockAPI.Net
get { return PacketTypes.PlayerSpawn; }
}
- public int TileX { get; set; }
- public int TileY { get; set; }
+ public short TileX { get; set; }
+ public short TileY { get; set; }
public byte PlayerIndex { get; set; }
public override void Pack(Stream stream)
diff --git a/TShockAPI/Net/WorldInfoMsg.cs b/TShockAPI/Net/WorldInfoMsg.cs
index 772cb314..e4763bb6 100644
--- a/TShockAPI/Net/WorldInfoMsg.cs
+++ b/TShockAPI/Net/WorldInfoMsg.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -20,6 +20,7 @@ using System;
using System.IO;
using System.IO.Streams;
using System.Text;
+using Terraria;
namespace TShockAPI.Net
{
@@ -33,7 +34,8 @@ namespace TShockAPI.Net
DownedBoss3 = 8,
HardMode = 16,
DownedClown = 32,
- ServerSideCharacter = 64
+ ServerSideCharacter = 64,
+ DownedPlantBoss = 128
}
[Flags]
@@ -46,7 +48,8 @@ namespace TShockAPI.Net
DownedMechBossAny = 8,
CloudBg = 16,
Crimson = 32,
- Pumpkin = 64
+ PumpkinMoon = 64,
+ SnowMoon = 128
}
public class WorldInfoMsg : BaseMsg
@@ -56,12 +59,12 @@ namespace TShockAPI.Net
public byte MoonPhase { get; set; }
public bool BloodMoon { get; set; }
public bool Eclipse { get; set; }
- public int MaxTilesX { get; set; }
- public int MaxTilesY { get; set; }
- public int SpawnX { get; set; }
- public int SpawnY { get; set; }
- public int WorldSurface { get; set; }
- public int RockLayer { get; set; }
+ public short MaxTilesX { get; set; }
+ public short MaxTilesY { get; set; }
+ public short SpawnX { get; set; }
+ public short SpawnY { get; set; }
+ public short WorldSurface { get; set; }
+ public short RockLayer { get; set; }
public int WorldID { get; set; }
public byte MoonType { get; set; }
public int TreeX0 { get; set; }
@@ -103,50 +106,71 @@ namespace TShockAPI.Net
public override void Pack(Stream stream)
{
- stream.WriteInt32(Time);
- stream.WriteBoolean(DayTime);
- stream.WriteInt8(MoonPhase);
- stream.WriteBoolean(BloodMoon);
- stream.WriteBoolean(Eclipse);
- stream.WriteInt32(MaxTilesX);
- stream.WriteInt32(MaxTilesY);
- stream.WriteInt32(SpawnX);
- stream.WriteInt32(SpawnY);
- stream.WriteInt32(WorldSurface);
- stream.WriteInt32(RockLayer);
- stream.WriteInt32(WorldID);
- stream.WriteByte(MoonType);
- stream.WriteInt32(TreeX0);
- stream.WriteInt32(TreeX1);
- stream.WriteInt32(TreeX2);
- stream.WriteByte(TreeStyle0);
- stream.WriteByte(TreeStyle1);
- stream.WriteByte(TreeStyle2);
- stream.WriteByte(TreeStyle3);
- stream.WriteInt32(CaveBackX0);
- stream.WriteInt32(CaveBackX1);
- stream.WriteInt32(CaveBackX2);
- stream.WriteByte(CaveBackStyle0);
- stream.WriteByte(CaveBackStyle1);
- stream.WriteByte(CaveBackStyle2);
- stream.WriteByte(CaveBackStyle3);
- stream.WriteByte(SetBG0);
- stream.WriteByte(SetBG1);
- stream.WriteByte(SetBG2);
- stream.WriteByte(SetBG3);
- stream.WriteByte(SetBG4);
- stream.WriteByte(SetBG5);
- stream.WriteByte(SetBG6);
- stream.WriteByte(SetBG7);
- stream.WriteByte(IceBackStyle);
- stream.WriteByte(JungleBackStyle);
- stream.WriteByte(HellBackStyle);
- stream.WriteSingle(WindSpeed);
- stream.WriteByte(NumberOfClouds);
- stream.WriteInt8((byte)BossFlags);
- stream.WriteInt8((byte)BossFlags2);
- stream.WriteSingle(Rain);
- stream.WriteBytes(Encoding.UTF8.GetBytes(WorldName));
+ BinaryWriter writer = new BinaryWriter(stream);
+ writer.Write(Time);
+ BitsByte worldinfo = new BitsByte(DayTime, BloodMoon, Eclipse);
+ writer.Write(worldinfo);
+ writer.Write(MoonPhase);
+ writer.Write(MaxTilesX);
+ writer.Write(MaxTilesY);
+ writer.Write(SpawnX);
+ writer.Write(SpawnY);
+ writer.Write(WorldSurface);
+ writer.Write(RockLayer);
+ writer.Write(WorldID);
+ writer.Write(WorldName);
+ writer.Write(MoonType);
+
+ writer.Write(SetBG0);
+ writer.Write(SetBG1);
+ writer.Write(SetBG2);
+ writer.Write(SetBG3);
+ writer.Write(SetBG4);
+ writer.Write(SetBG5);
+ writer.Write(SetBG6);
+ writer.Write(SetBG7);
+ writer.Write(IceBackStyle);
+ writer.Write(JungleBackStyle);
+ writer.Write(HellBackStyle);
+ writer.Write(WindSpeed);
+ writer.Write(NumberOfClouds);
+
+ writer.Write(TreeX0);
+ writer.Write(TreeX1);
+ writer.Write(TreeX2);
+ writer.Write(TreeStyle0);
+ writer.Write(TreeStyle1);
+ writer.Write(TreeStyle2);
+ writer.Write(TreeStyle3);
+ writer.Write(CaveBackX0);
+ writer.Write(CaveBackX1);
+ writer.Write(CaveBackX2);
+ writer.Write(CaveBackStyle0);
+ writer.Write(CaveBackStyle1);
+ writer.Write(CaveBackStyle2);
+ writer.Write(CaveBackStyle3);
+
+ writer.Write(Rain);
+
+ BitsByte bosses1 = new BitsByte((BossFlags & BossFlags.OrbSmashed) == BossFlags.OrbSmashed,
+ (BossFlags & BossFlags.DownedBoss1) == BossFlags.DownedBoss1,
+ (BossFlags & BossFlags.DownedBoss2) == BossFlags.DownedBoss2,
+ (BossFlags & BossFlags.DownedBoss3) == BossFlags.DownedBoss3,
+ (BossFlags & BossFlags.HardMode) == BossFlags.HardMode,
+ (BossFlags & BossFlags.DownedClown) == BossFlags.DownedClown,
+ (BossFlags & BossFlags.ServerSideCharacter) == BossFlags.ServerSideCharacter,
+ (BossFlags & BossFlags.DownedPlantBoss) == BossFlags.DownedPlantBoss);
+ writer.Write(bosses1);
+
+ BitsByte bosses2 = new BitsByte((BossFlags2 & BossFlags2.DownedMechBoss1) == BossFlags2.DownedMechBoss1,
+ (BossFlags2 & BossFlags2.DownedMechBoss2) == BossFlags2.DownedMechBoss2,
+ (BossFlags2 & BossFlags2.DownedMechBoss3) == BossFlags2.DownedMechBoss3,
+ (BossFlags2 & BossFlags2.DownedMechBossAny) == BossFlags2.DownedMechBossAny,
+ (BossFlags2 & BossFlags2.CloudBg) == BossFlags2.CloudBg,
+ (BossFlags2 & BossFlags2.Crimson) == BossFlags2.Crimson,
+ (BossFlags2 & BossFlags2.PumpkinMoon) == BossFlags2.PumpkinMoon,
+ (BossFlags2 & BossFlags2.SnowMoon) == BossFlags2.SnowMoon);
+ writer.Write(bosses2);
}
}
}
\ No newline at end of file
diff --git a/TShockAPI/PacketBufferer.cs b/TShockAPI/PacketBufferer.cs
index e916d74f..051a9531 100644
--- a/TShockAPI/PacketBufferer.cs
+++ b/TShockAPI/PacketBufferer.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -197,32 +197,45 @@ namespace TShockAPI
{
if (socket.tcpClient.Client != null && socket.tcpClient.Client.Poll(0, SelectMode.SelectWrite))
{
- if (Main.runningMono)
+ if (ServerApi.RunningMono && !ServerApi.UseAsyncSocketsInMono)
socket.networkStream.Write(buffer, offset, count);
else
- socket.tcpClient.Client.Send(buffer, offset, count, SocketFlags.None);
+ socket.networkStream.BeginWrite(buffer, offset, count, socket.ServerWriteCallBack, socket.networkStream);
return true;
}
}
catch (ObjectDisposedException e)
{
- Log.Warn(e.ToString());
+ Log.Warn(e.ToString());
}
catch (SocketException e)
{
- switch ((uint)e.ErrorCode)
- {
- case 0x80004005:
+ switch ((uint)e.ErrorCode)
+ {
+ case 0x80004005:
case 10053:
- break;
- default:
- Log.Warn(e.ToString());
- break;
- }
+ break;
+ default:
+ Log.Warn(e.ToString());
+ break;
+ }
}
catch (IOException e)
{
- Log.Warn(e.ToString());
+ if (e.InnerException is SocketException)
+ {
+ switch (((SocketException)e.InnerException).SocketErrorCode)
+ {
+ case SocketError.Shutdown:
+ case SocketError.ConnectionReset:
+ break;
+ default:
+ Log.Warn(e.ToString());
+ break;
+ }
+ }
+ else
+ Log.Warn(e.ToString());
}
return false;
}
diff --git a/TShockAPI/PaginationTools.cs b/TShockAPI/PaginationTools.cs
index 75de305d..e3161a3c 100644
--- a/TShockAPI/PaginationTools.cs
+++ b/TShockAPI/PaginationTools.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs
index 4f7d68f4..d970182a 100644
--- a/TShockAPI/Permissions.cs
+++ b/TShockAPI/Permissions.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -64,6 +64,12 @@ namespace TShockAPI
[Description("User can manage item bans.")]
public static readonly string manageitem = "tshock.admin.itemban";
+ [Description("User can manage projectile bans.")]
+ public static readonly string manageprojectile = "tshock.admin.projectileban";
+
+ [Description("User can manage tile bans.")]
+ public static readonly string managetile = "tshock.admin.tileban";
+
[Description("User can manage groups.")]
public static readonly string managegroup = "tshock.admin.group";
@@ -139,8 +145,8 @@ namespace TShockAPI
[Description("Prevents your actions from being ignored if damage is too high.")]
public static readonly string ignoredamagecap = "tshock.ignore.damage";
- [Description("Bypass server side inventory checks")]
- public static readonly string bypassinventorychecks = "tshock.ignore.ssi";
+ [Description("Bypass server side character checks")]
+ public static readonly string bypassssc = "tshock.ignore.ssc";
[Description("Allow unrestricted SendTileSquare usage, for client side world editing.")]
public static readonly string allowclientsideworldedit = "tshock.ignore.sendtilesquare";
@@ -148,6 +154,12 @@ namespace TShockAPI
[Description("Allow dropping banned items without the item being eaten.")]
public static readonly string allowdroppingbanneditems = "tshock.ignore.dropbanneditem";
+ [Description("Prevents you from being disabled by abnormal HP.")]
+ public static readonly string ignorehp = "tshock.ignore.hp";
+
+ [Description("Prevents you from being disabled by abnormal MP.")]
+ public static readonly string ignoremp = "tshock.ignore.mp";
+
// tshock.item nodes
[Description("User can spawn items.")]
@@ -167,9 +179,15 @@ namespace TShockAPI
[Description("User can start an invasion.")]
public static readonly string invade = "tshock.npc.invade";
+ [Description("User can hurt town NPCs.")]
+ public static readonly string hurttownnpc = "tshock.npc.hurttown";
+
[Description("User can spawn bosses.")]
public static readonly string spawnboss = "tshock.npc.spawnboss";
+ [Description("User can rename NPCs.")]
+ public static readonly string renamenpc = "tshock.npc.rename";
+
[Description("User can spawn npcs.")]
public static readonly string spawnmob = "tshock.npc.spawnmob";
@@ -182,6 +200,9 @@ namespace TShockAPI
[Description("User can start invasions (Goblin/Snow Legion) using items")]
public static readonly string startinvasion = "tshock.npc.startinvasion";
+ [Description("User can clear the list of users who have completed an angler quest that day.")]
+ public static readonly string clearangler = "tshock.npc.clearanglerquests";
+
// tshock.superadmin nodes
[Description("Meant for super admins only.")]
@@ -192,20 +213,29 @@ namespace TShockAPI
// tshock.tp nodes
+ [Description("User can teleport *everyone* to them.")]
+ public static readonly string tpallothers = "tshock.tp.allothers";
+
[Description("User can teleport to others.")]
public static readonly string tp = "tshock.tp.self";
- [Description("User can teleport people to them.")]
- public static readonly string tphere = "tshock.tp.others";
+ [Description("User can teleport other people.")]
+ public static readonly string tpothers = "tshock.tp.others";
- [Description("Users can stop people from teleporting to them")]
+ [Description("User can teleport to tile positions.")]
+ public static readonly string tppos = "tshock.tp.pos";
+
+ [Description("User can teleport to an NPC.")]
+ public static readonly string tpnpc = "tshock.tp.npc";
+
+ [Description("Users can stop people from teleporting.")]
public static readonly string tpallow = "tshock.tp.block";
- [Description("Users can tp to anyone")]
- public static readonly string tpall = "tshock.tp.toall";
+ [Description("Users can override teleport blocks.")]
+ public static readonly string tpoverride = "tshock.tp.override";
- [Description("Users can tp to people without showing a notice")]
- public static readonly string tphide = "tshock.tp.silent";
+ [Description("Users can teleport to people without showing a notice")]
+ public static readonly string tpsilent = "tshock.tp.silent";
[Description("User can use /home.")]
public static readonly string home = "tshock.tp.home";
@@ -227,12 +257,6 @@ namespace TShockAPI
[Description("User can force a blood moon.")]
public static readonly string bloodmoon = "tshock.world.time.bloodmoon";
- [Description("User can force a pumpkin moon.")]
- public static readonly string pumpkinmoon = "tshock.world.time.pumpkinmoon";
-
- [Description("User can force a snow moon.")]
- public static readonly string snowmoon = "tshock.world.time.snowmoon";
-
[Description("User can set the time.")]
public static readonly string time = "tshock.world.time.set";
@@ -248,6 +272,9 @@ namespace TShockAPI
[Description("User can convert hallow into corruption and vice-versa")]
public static readonly string converthardmode = "tshock.world.converthardmode";
+ [Description("User can force the server to Halloween mode.")]
+ public static readonly string halloween = "tshock.world.sethalloween";
+
[Description("User can force the server to Christmas mode.")]
public static readonly string xmas = "tshock.world.setxmas";
@@ -281,6 +308,9 @@ namespace TShockAPI
[Description("User can turn on or off the rain.")]
public static readonly string rain = "tshock.world.rain";
+ [Description("User can modify the wind.")]
+ public static readonly string wind = "tshock.world.wind";
+
// Non-grouped
[Description("User can clear items or projectiles.")]
@@ -288,7 +318,7 @@ namespace TShockAPI
[Description("User can kill others.")]
public static readonly string kill = "tshock.kill";
-
+
[Description("Allows you to bypass the max slots for up to 5 slots above your max.")]
public static readonly string reservedslot = "tshock.reservedslot";
@@ -322,11 +352,17 @@ namespace TShockAPI
[Description("Player can chat")]
public static readonly string canchat = "tshock.canchat";
- ///
- /// Lists all commands associated with a given permission
- ///
- /// string permission - the permission to get information on
- /// List of commands
+ [Description("Player can use banned projectiles.")]
+ public static readonly string canusebannedprojectiles = "tshock.projectiles.usebanned";
+
+ [Description("Player can place banned tiles.")]
+ public static readonly string canusebannedtiles = "tshock.tiles.usebanned";
+
+ ///
+ /// Lists all commands associated with a given permission
+ ///
+ /// string permission - the permission to get information on
+ /// List of commands
private static List GetCommands(string perm)
{
if (Commands.ChatCommands.Count < 1)
@@ -334,9 +370,9 @@ namespace TShockAPI
return Commands.ChatCommands.Where(c => c.Permissions.Contains(perm)).ToList();
}
- ///
- /// Dumps the descriptions of each permission to a file in Markdown format.
- ///
+ ///
+ /// Dumps the descriptions of each permission to a file in Markdown format.
+ ///
public static void DumpDescriptions()
{
var sb = new StringBuilder();
@@ -385,4 +421,4 @@ namespace TShockAPI
{
}
}
-}
\ No newline at end of file
+}
diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs
old mode 100644
new mode 100755
index 1ce5b404..61a58e2a
--- a/TShockAPI/Properties/AssemblyInfo.cs
+++ b/TShockAPI/Properties/AssemblyInfo.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -28,7 +28,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Nyx Studios & TShock Contributors")]
[assembly: AssemblyProduct("TShockAPI")]
-[assembly: AssemblyCopyright("Copyright © Nyx Studios 2011-2013")]
+[assembly: AssemblyCopyright("Copyright © Nyx Studios 2011-2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -47,7 +47,11 @@ using System.Runtime.InteropServices;
// Major Version
// Minor Version
// Build Number
-// MMdd of the build
+// Starting in version 4.2.5, we are no longer including the fourth decimal
+// location, which previously held the date and time.
-[assembly: AssemblyVersion("4.2.2.1228")]
-[assembly: AssemblyFileVersion("4.2.2.1228")]
+// Also, be sure to release on github with the exact assembly version tag as below
+// so that the update manager works correctly (via the Github releases api and mimic)
+
+[assembly: AssemblyVersion("4.2.5")]
+[assembly: AssemblyFileVersion("4.2.5")]
diff --git a/TShockAPI/RaptorPacketTypes.cs b/TShockAPI/RaptorPacketTypes.cs
deleted file mode 100644
index 81a6f125..00000000
--- a/TShockAPI/RaptorPacketTypes.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace TShockAPI
-{
- ///
- /// Custom packet types for use with Raptor.
- ///
- public enum RaptorPacketTypes : byte
- {
- ///
- /// The packet sent to the server to be acknowledged as a Raptor client.
- ///
- Acknowledge = 0,
- ///
- /// The packet sent to the client which dictates its permissions.
- ///
- Permissions,
- ///
- /// The packet sent which sets region info.
- ///
- Region,
- ///
- /// The packet sent to delete a region.
- ///
- RegionDelete,
- ///
- /// The packet sent which sets warp info.
- ///
- Warp,
- ///
- /// The packet sent to delete a warp.
- ///
- WarpDelete
- }
-}
diff --git a/TShockAPI/RconHandler.cs b/TShockAPI/RconHandler.cs
index 3e83f856..39f32fa2 100644
--- a/TShockAPI/RconHandler.cs
+++ b/TShockAPI/RconHandler.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Rest/Rest.cs b/TShockAPI/Rest/Rest.cs
index 32a5328c..c23d0552 100644
--- a/TShockAPI/Rest/Rest.cs
+++ b/TShockAPI/Rest/Rest.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -37,17 +37,31 @@ namespace Rests
/// Parameters in the url
/// {x} in urltemplate
/// Response object or null to not handle request
- public delegate object RestCommandD(RestVerbs verbs, IParameterCollection parameters);
+ public delegate object RestCommandD(RestRequestArgs args);
- ///
- /// Secure Rest command delegate including token data.
- ///
- /// Parameters in the url
- /// {x} in urltemplate
- /// The data of stored for the provided token.
- /// Response object or null to not handle request
- public delegate object SecureRestCommandD(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData);
+ public class RestRequestArgs
+ {
+ public RestVerbs Verbs { get; private set; }
+ public IParameterCollection Parameters { get; private set; }
+ public IRequest Request { get; private set; }
+ public SecureRest.TokenData TokenData { get; private set; }
+ public RestRequestArgs(RestVerbs verbs, IParameterCollection param, IRequest request)
+ {
+ Verbs = verbs;
+ Parameters = param;
+ Request = request;
+ TokenData = SecureRest.TokenData.None;
+ }
+
+ public RestRequestArgs(RestVerbs verbs, IParameterCollection param, IRequest request, SecureRest.TokenData tokenData)
+ {
+ Verbs = verbs;
+ Parameters = param;
+ Request = request;
+ TokenData = tokenData;
+ }
+ }
public class Rest : IDisposable
{
private readonly List commands = new List();
@@ -173,7 +187,7 @@ namespace Rests
continue;
}
- var obj = ExecuteCommand(com, verbs, e.Request.Parameters);
+ var obj = ExecuteCommand(com, verbs, e.Request.Parameters, e.Request);
if (obj != null)
return obj;
}
@@ -193,9 +207,9 @@ namespace Rests
};
}
- protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
+ protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms, IRequest request)
{
- object result = cmd.Execute(verbs, parms);
+ object result = cmd.Execute(verbs, parms, request);
if (cmd.DoLog && TShock.Config.LogRest)
{
Log.ConsoleInfo("Anonymous requested REST endpoint: " + BuildRequestUri(cmd, verbs, parms, false));
diff --git a/TShockAPI/Rest/RestCommand.cs b/TShockAPI/Rest/RestCommand.cs
index c0db0a9a..681d7cbf 100644
--- a/TShockAPI/Rest/RestCommand.cs
+++ b/TShockAPI/Rest/RestCommand.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -65,9 +65,9 @@ namespace Rests
get { return UriVerbs.Length > 0; }
}
- public virtual object Execute(RestVerbs verbs, IParameterCollection parameters)
+ public virtual object Execute(RestVerbs verbs, IParameterCollection parameters, IRequest request)
{
- return callback(verbs, parameters);
+ return callback(new RestRequestArgs(verbs, parameters, request));
}
}
@@ -76,31 +76,31 @@ namespace Rests
public override bool RequiresToken { get { return true; } }
public string[] Permissions { get; set; }
- private SecureRestCommandD callback;
+ private RestCommandD callback;
- public SecureRestCommand(string name, string uritemplate, SecureRestCommandD callback, params string[] permissions)
+ public SecureRestCommand(string name, string uritemplate, RestCommandD callback, params string[] permissions)
: base(name, uritemplate, null)
{
this.callback = callback;
Permissions = permissions;
}
- public SecureRestCommand(string uritemplate, SecureRestCommandD callback, params string[] permissions)
+ public SecureRestCommand(string uritemplate, RestCommandD callback, params string[] permissions)
: this(string.Empty, uritemplate, callback, permissions)
{
}
- public override object Execute(RestVerbs verbs, IParameterCollection parameters)
+ public override object Execute(RestVerbs verbs, IParameterCollection parameters, IRequest request)
{
return new RestObject("401") { Error = "Not authorized. The specified API endpoint requires a token." };
}
- public object Execute(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ public object Execute(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData, IRequest request)
{
if (tokenData.Equals(SecureRest.TokenData.None))
return new RestObject("401") { Error = "Not authorized. The specified API endpoint requires a token." };
- return callback(verbs, parameters, tokenData);
+ return callback(new RestRequestArgs(verbs, parameters, request, tokenData));
}
}
}
\ No newline at end of file
diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs
index a4ad0502..93d81eee 100644
--- a/TShockAPI/Rest/RestManager.cs
+++ b/TShockAPI/Rest/RestManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -49,10 +49,10 @@ namespace TShockAPI
}
else
{
- Rest.Register(new RestCommand("/v2/server/status", (a, b) => this.ServerStatusV2(a, b, SecureRest.TokenData.None)));
- Rest.Register(new RestCommand("/status", (a, b) => this.ServerStatus(a, b, SecureRest.TokenData.None)));
- Rest.Register(new RestCommand("/v3/server/motd", (a, b) => this.ServerMotd(a, b, SecureRest.TokenData.None)));
- Rest.Register(new RestCommand("/v3/server/rules", (a, b) => this.ServerRules(a, b, SecureRest.TokenData.None)));
+ Rest.Register(new RestCommand("/v2/server/status", (a) => this.ServerStatusV2(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None))));
+ Rest.Register(new RestCommand("/status", (a) => this.ServerStatus(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None))));
+ Rest.Register(new RestCommand("/v3/server/motd", (a) => this.ServerMotd(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None))));
+ Rest.Register(new RestCommand("/v3/server/rules", (a) => this.ServerRules(new RestRequestArgs(a.Verbs, a.Parameters, a.Request, SecureRest.TokenData.None))));
}
Rest.Register(new SecureRestCommand("/v2/server/broadcast", ServerBroadcast));
@@ -89,6 +89,7 @@ namespace TShockAPI
Rest.Register(new SecureRestCommand("/lists/players", PlayerList));
Rest.Register(new SecureRestCommand("/v2/players/list", PlayerListV2));
Rest.Register(new SecureRestCommand("/v2/players/read", PlayerReadV2, RestPermissions.restuserinfo));
+ Rest.Register(new SecureRestCommand("/v3/players/read", PlayerReadV3, RestPermissions.restuserinfo));
Rest.Register(new SecureRestCommand("/v2/players/kick", PlayerKickV2, RestPermissions.restkick));
Rest.Register(new SecureRestCommand("/v2/players/ban", PlayerBanV2, RestPermissions.restban, RestPermissions.restmanagebans));
Rest.Register(new SecureRestCommand("/v2/players/kill", PlayerKill, RestPermissions.restkill));
@@ -105,84 +106,84 @@ namespace TShockAPI
#region RestServerMethods
- private object ServerCommand(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerCommand(RestRequestArgs args)
{
- if (string.IsNullOrWhiteSpace(parameters["cmd"]))
+ if (string.IsNullOrWhiteSpace(args.Parameters["cmd"]))
return RestMissingParam("cmd");
Group restPlayerGroup;
// TODO: Get rid of this when the old REST permission model is removed.
if (TShock.Config.RestUseNewPermissionModel)
- restPlayerGroup = TShock.Groups.GetGroupByName(tokenData.UserGroupName);
+ restPlayerGroup = TShock.Groups.GetGroupByName(args.TokenData.UserGroupName);
else
restPlayerGroup = new SuperAdminGroup();
- TSRestPlayer tr = new TSRestPlayer(tokenData.Username, restPlayerGroup);
- Commands.HandleCommand(tr, parameters["cmd"]);
+ TSRestPlayer tr = new TSRestPlayer(args.TokenData.Username, restPlayerGroup);
+ Commands.HandleCommand(tr, args.Parameters["cmd"]);
return RestResponse(string.Join("\n", tr.GetCommandOutput()));
}
- private object ServerCommandV3(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerCommandV3(RestRequestArgs args)
{
- if (string.IsNullOrWhiteSpace(parameters["cmd"]))
+ if (string.IsNullOrWhiteSpace(args.Parameters["cmd"]))
return RestMissingParam("cmd");
Group restPlayerGroup;
// TODO: Get rid of this when the old REST permission model is removed.
if (TShock.Config.RestUseNewPermissionModel)
- restPlayerGroup = TShock.Groups.GetGroupByName(tokenData.UserGroupName);
+ restPlayerGroup = TShock.Groups.GetGroupByName(args.TokenData.UserGroupName);
else
restPlayerGroup = new SuperAdminGroup();
- TSRestPlayer tr = new TSRestPlayer(tokenData.Username, restPlayerGroup);
- Commands.HandleCommand(tr, parameters["cmd"]);
+ TSRestPlayer tr = new TSRestPlayer(args.TokenData.Username, restPlayerGroup);
+ Commands.HandleCommand(tr, args.Parameters["cmd"]);
return new RestObject()
{
{"response", tr.GetCommandOutput()}
};
}
- private object ServerOff(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerOff(RestRequestArgs args)
{
- if (!GetBool(parameters["confirm"], false))
+ if (!GetBool(args.Parameters["confirm"], false))
return RestInvalidParam("confirm");
// Inform players the server is shutting down
- var reason = string.IsNullOrWhiteSpace(parameters["message"]) ? "Server is shutting down" : parameters["message"];
- TShock.Utils.StopServer(!GetBool(parameters["nosave"], false), reason);
+ var reason = string.IsNullOrWhiteSpace(args.Parameters["message"]) ? "Server is shutting down" : args.Parameters["message"];
+ TShock.Utils.StopServer(!GetBool(args.Parameters["nosave"], false), reason);
return RestResponse("The server is shutting down");
}
- private object ServerRestart(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerRestart(RestRequestArgs args)
{
- if (!GetBool(parameters["confirm"], false))
+ if (!GetBool(args.Parameters["confirm"], false))
return RestInvalidParam("confirm");
// Inform players the server is shutting down
- var reason = string.IsNullOrWhiteSpace(parameters["message"]) ? "Server is restarting" : parameters["message"];
- TShock.Utils.RestartServer(!GetBool(parameters["nosave"], false), reason);
+ var reason = string.IsNullOrWhiteSpace(args.Parameters["message"]) ? "Server is restarting" : args.Parameters["message"];
+ TShock.Utils.RestartServer(!GetBool(args.Parameters["nosave"], false), reason);
return RestResponse("The server is shutting down and will attempt to restart");
}
- private object ServerReload(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerReload(RestRequestArgs args)
{
- TShock.Utils.Reload(new TSRestPlayer(tokenData.Username, TShock.Groups.GetGroupByName(tokenData.UserGroupName)));
+ TShock.Utils.Reload(new TSRestPlayer(args.TokenData.Username, TShock.Groups.GetGroupByName(args.TokenData.UserGroupName)));
return RestResponse("Configuration, permissions, and regions reload complete. Some changes may require a server restart.");
}
- private object ServerBroadcast(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerBroadcast(RestRequestArgs args)
{
- var msg = parameters["msg"];
+ var msg = args.Parameters["msg"];
if (string.IsNullOrWhiteSpace(msg))
return RestMissingParam("msg");
TShock.Utils.Broadcast(msg);
return RestResponse("The message was broadcasted successfully");
}
- private object ServerMotd(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerMotd(RestRequestArgs args)
{
string motdFilePath = Path.Combine(TShock.SavePath, "motd.txt");
if (!File.Exists(motdFilePath))
@@ -194,7 +195,7 @@ namespace TShockAPI
};
}
- private object ServerRules(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerRules(RestRequestArgs args)
{
string rulesFilePath = Path.Combine(TShock.SavePath, "rules.txt");
if (!File.Exists(rulesFilePath))
@@ -206,7 +207,7 @@ namespace TShockAPI
};
}
- private object ServerStatus(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerStatus(RestRequestArgs args)
{
var activeplayers = Main.player.Where(p => null != p && p.active).ToList();
return new RestObject()
@@ -218,11 +219,13 @@ namespace TShockAPI
};
}
- private object ServerStatusV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerStatusV2(RestRequestArgs args)
{
var ret = new RestObject()
{
{"name", TShock.Config.ServerName},
+ {"serverversion", Main.versionNumber},
+ {"tshockversion", TShock.VersionNum},
{"port", TShock.Config.ServerPort},
{"playercount", Main.player.Where(p => null != p && p.active).Count()},
{"maxplayers", TShock.Config.MaxSlots},
@@ -231,19 +234,19 @@ namespace TShockAPI
{"serverpassword", !string.IsNullOrEmpty(TShock.Config.ServerPassword)}
};
- if (GetBool(parameters["players"], false))
+ if (GetBool(args.Parameters["players"], false))
{
var players = new ArrayList();
foreach (TSPlayer tsPlayer in TShock.Players.Where(p => null != p))
{
- var p = PlayerFilter(tsPlayer, parameters, ((tokenData.UserGroupName) != "" && TShock.Utils.GetGroup(tokenData.UserGroupName).HasPermission(RestPermissions.viewips)));
+ var p = PlayerFilter(tsPlayer, args.Parameters, ((args.TokenData.UserGroupName) != "" && TShock.Utils.GetGroup(args.TokenData.UserGroupName).HasPermission(RestPermissions.viewips)));
if (null != p)
players.Add(p);
}
ret.Add("players", players);
}
- if (GetBool(parameters["rules"], false))
+ if (GetBool(args.Parameters["rules"], false))
{
var rules = new Dictionary();
rules.Add("AutoSave", TShock.Config.AutoSave);
@@ -258,19 +261,19 @@ namespace TShockAPI
rules.Add("PvPMode", TShock.Config.PvPMode);
rules.Add("SpawnProtection", TShock.Config.SpawnProtection);
rules.Add("SpawnProtectionRadius", TShock.Config.SpawnProtectionRadius);
- rules.Add("ServerSideInventory", TShock.Config.ServerSideCharacter);
+ rules.Add("ServerSideInventory", Main.ServerSideCharacter);
ret.Add("rules", rules);
}
return ret;
}
- private object ServerTokenTest(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object ServerTokenTest(RestRequestArgs args)
{
return new RestObject()
{
{"response", "Token is valid and was passed through correctly."},
- {"associateduser", tokenData.Username}
+ {"associateduser", args.TokenData.Username}
};
}
@@ -278,12 +281,12 @@ namespace TShockAPI
#region RestUserMethods
- private object UserActiveListV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object UserActiveListV2(RestRequestArgs args)
{
return new RestObject() { { "activeusers", string.Join("\t", TShock.Players.Where(p => null != p && null != p.UserAccountName && p.Active).Select(p => p.UserAccountName)) } };
}
- private object UserListV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object UserListV2(RestRequestArgs args)
{
return new RestObject() { { "users", TShock.Users.GetUsers().Select(p => new Dictionary(){
{"name", p.Name},
@@ -292,17 +295,17 @@ namespace TShockAPI
}) } };
}
- private object UserCreateV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object UserCreateV2(RestRequestArgs args)
{
- var username = parameters["user"];
+ var username = args.Parameters["user"];
if (string.IsNullOrWhiteSpace(username))
return RestMissingParam("user");
- var group = parameters["group"];
+ var group = args.Parameters["group"];
if (string.IsNullOrWhiteSpace(group))
group = TShock.Config.DefaultRegistrationGroupName;
- var password = parameters["password"];
+ var password = args.Parameters["password"];
if (string.IsNullOrWhiteSpace(password))
return RestMissingParam("password");
@@ -320,14 +323,14 @@ namespace TShockAPI
return RestResponse("User was successfully created");
}
- private object UserUpdateV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object UserUpdateV2(RestRequestArgs args)
{
- var ret = UserFind(parameters);
+ var ret = UserFind(args.Parameters);
if (ret is RestObject)
return ret;
- var password = parameters["password"];
- var group = parameters["group"];
+ var password = args.Parameters["password"];
+ var group = args.Parameters["group"];
if (string.IsNullOrWhiteSpace(group) && string.IsNullOrWhiteSpace(password))
return RestMissingParam("group", "password");
@@ -362,9 +365,9 @@ namespace TShockAPI
return response;
}
- private object UserDestroyV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object UserDestroyV2(RestRequestArgs args)
{
- var ret = UserFind(parameters);
+ var ret = UserFind(args.Parameters);
if (ret is RestObject)
return ret;
@@ -380,9 +383,9 @@ namespace TShockAPI
return RestResponse("User deleted successfully");
}
- private object UserInfoV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object UserInfoV2(RestRequestArgs args)
{
- var ret = UserFind(parameters);
+ var ret = UserFind(args.Parameters);
if (ret is RestObject)
return ret;
@@ -394,17 +397,17 @@ namespace TShockAPI
#region RestBanMethods
- private object BanCreate(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object BanCreate(RestRequestArgs args)
{
- var ip = parameters["ip"];
- var name = parameters["name"];
+ var ip = args.Parameters["ip"];
+ var name = args.Parameters["name"];
if (string.IsNullOrWhiteSpace(ip) && string.IsNullOrWhiteSpace(name))
return RestMissingParam("ip", "name");
try
{
- TShock.Bans.AddBan(ip, name, "", parameters["reason"], true, tokenData.Username);
+ TShock.Bans.AddBan(ip, name, "", args.Parameters["reason"], true, args.TokenData.Username);
}
catch (Exception e)
{
@@ -413,27 +416,27 @@ namespace TShockAPI
return RestResponse("Ban created successfully");
}
- private object BanDestroyV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object BanDestroyV2(RestRequestArgs args)
{
- var ret = BanFind(parameters);
+ var ret = BanFind(args.Parameters);
if (ret is RestObject)
return ret;
try
{
Ban ban = (Ban)ret;
- switch (parameters["type"])
+ switch (args.Parameters["type"])
{
case "ip":
if (!TShock.Bans.RemoveBan(ban.IP, false, false, true))
return RestResponse("Failed to delete ban (already deleted?)");
break;
case "name":
- if (!TShock.Bans.RemoveBan(ban.Name, true, GetBool(parameters["caseinsensitive"], true)))
+ if (!TShock.Bans.RemoveBan(ban.Name, true, GetBool(args.Parameters["caseinsensitive"], true)))
return RestResponse("Failed to delete ban (already deleted?)");
break;
default:
- return RestError("Invalid Type: '" + parameters["type"] + "'");
+ return RestError("Invalid Type: '" + args.Parameters["type"] + "'");
}
}
@@ -445,9 +448,9 @@ namespace TShockAPI
return RestResponse("Ban deleted successfully");
}
- private object BanInfoV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object BanInfoV2(RestRequestArgs args)
{
- var ret = BanFind(parameters);
+ var ret = BanFind(args.Parameters);
if (ret is RestObject)
return ret;
@@ -459,7 +462,7 @@ namespace TShockAPI
};
}
- private object BanListV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object BanListV2(RestRequestArgs args)
{
var banList = new ArrayList();
foreach (var ban in TShock.Bans.GetBans())
@@ -481,32 +484,29 @@ namespace TShockAPI
#region RestWorldMethods
- private object WorldChangeSaveSettings(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object WorldChangeSaveSettings(RestRequestArgs args)
{
bool autoSave;
- if (!bool.TryParse(verbs["bool"], out autoSave))
+ if (!bool.TryParse(args.Verbs["bool"], out autoSave))
return RestInvalidParam("state");
TShock.Config.AutoSave = autoSave;
return RestResponse("AutoSave has been set to " + autoSave);
}
- private object WorldSave(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object WorldSave(RestRequestArgs args)
{
SaveManager.Instance.SaveWorld();
return RestResponse("World saved");
}
- private object WorldButcher(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object WorldButcher(RestRequestArgs args)
{
bool killFriendly;
- if (!bool.TryParse(parameters["killfriendly"], out killFriendly))
+ if (!bool.TryParse(args.Parameters["killfriendly"], out killFriendly))
return RestInvalidParam("killfriendly");
- if (killFriendly)
- killFriendly = !killFriendly;
-
int killcount = 0;
for (int i = 0; i < Main.npc.Length; i++)
{
@@ -520,7 +520,7 @@ namespace TShockAPI
return RestResponse(killcount + " NPCs have been killed");
}
- private object WorldRead(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object WorldRead(RestRequestArgs args)
{
return new RestObject()
{
@@ -533,7 +533,7 @@ namespace TShockAPI
};
}
- private object WorldMeteor(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object WorldMeteor(RestRequestArgs args)
{
if (null == WorldGen.genRand)
WorldGen.genRand = new Random();
@@ -541,10 +541,10 @@ namespace TShockAPI
return RestResponse("Meteor has been spawned");
}
- private object WorldBloodmoon(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object WorldBloodmoon(RestRequestArgs args)
{
bool bloodmoon;
- if (!bool.TryParse(verbs["bool"], out bloodmoon))
+ if (!bool.TryParse(args.Verbs["bool"], out bloodmoon))
return RestInvalidParam("bloodmoon");
Main.bloodMoon = bloodmoon;
@@ -555,37 +555,37 @@ namespace TShockAPI
#region RestPlayerMethods
- private object PlayerUnMute(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object PlayerUnMute(RestRequestArgs args)
{
- return PlayerSetMute(parameters, false);
+ return PlayerSetMute(args.Parameters, false);
}
- private object PlayerMute(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object PlayerMute(RestRequestArgs args)
{
- return PlayerSetMute(parameters, true);
+ return PlayerSetMute(args.Parameters, true);
}
- private object PlayerList(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object PlayerList(RestRequestArgs args)
{
var activeplayers = Main.player.Where(p => null != p && p.active).ToList();
return new RestObject() { { "players", string.Join(", ", activeplayers.Select(p => p.name)) } };
}
- private object PlayerListV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object PlayerListV2(RestRequestArgs args)
{
var playerList = new ArrayList();
foreach (TSPlayer tsPlayer in TShock.Players.Where(p => null != p))
{
- var p = PlayerFilter(tsPlayer, parameters);
+ var p = PlayerFilter(tsPlayer, args.Parameters);
if (null != p)
playerList.Add(p);
}
return new RestObject() { { "players", playerList } };
}
- private object PlayerReadV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object PlayerReadV2(RestRequestArgs args)
{
- var ret = PlayerFind(parameters);
+ var ret = PlayerFind(args.Parameters);
if (ret is RestObject)
return ret;
@@ -603,39 +603,63 @@ namespace TShockAPI
};
}
- private object PlayerKickV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object PlayerReadV3(RestRequestArgs args)
{
- var ret = PlayerFind(parameters);
+ var ret = PlayerFind(args.Parameters);
if (ret is RestObject)
return ret;
TSPlayer player = (TSPlayer)ret;
- TShock.Utils.ForceKick(player, null == parameters["reason"] ? "Kicked via web" : parameters["reason"], false, true);
+ var inventory = player.TPlayer.inventory.Where(p => p.active).ToList();
+ var equipment = player.TPlayer.armor.Where(p => p.active).ToList();
+ var dyes = player.TPlayer.dye.Where(p => p.active).ToList();
+ return new RestObject()
+ {
+ {"nickname", player.Name},
+ {"username", null == player.UserAccountName ? "" : player.UserAccountName},
+ {"ip", player.IP},
+ {"group", player.Group.Name},
+ {"position", player.TileX + "," + player.TileY},
+ {"inventory", string.Join(", ", inventory.Select(p => (p.name + ":" + p.stack)))},
+ {"armor", string.Join(", ", equipment.Select(p => (p.netID + ":" + p.prefix)))},
+ {"dyes", string.Join(", ", dyes.Select(p => (p.name)))},
+ {"buffs", string.Join(", ", player.TPlayer.buffType)}
+ };
+ }
+
+ private object PlayerKickV2(RestRequestArgs args)
+ {
+ var ret = PlayerFind(args.Parameters);
+ if (ret is RestObject)
+ return ret;
+
+ TSPlayer player = (TSPlayer)ret;
+ TShock.Utils.ForceKick(player, null == args.Parameters["reason"] ? "Kicked via web" : args.Parameters["reason"], false, true);
return RestResponse("Player " + player.Name + " was kicked");
}
- private object PlayerBanV2(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object PlayerBanV2(RestRequestArgs args)
{
- var ret = PlayerFind(parameters);
+ var ret = PlayerFind(args.Parameters);
if (ret is RestObject)
return ret;
TSPlayer player = (TSPlayer)ret;
- var reason = null == parameters["reason"] ? "Banned via web" : parameters["reason"];
+ var reason = null == args.Parameters["reason"] ? "Banned via web" : args.Parameters["reason"];
TShock.Bans.AddBan(player.IP, player.Name, "", reason);
TShock.Utils.ForceKick(player, reason, false, true);
return RestResponse("Player " + player.Name + " was banned");
}
- private object PlayerKill(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object PlayerKill(RestRequestArgs args)
{
- var ret = PlayerFind(parameters);
+ var ret = PlayerFind(args.Parameters);
if (ret is RestObject)
return ret;
TSPlayer player = (TSPlayer)ret;
player.DamagePlayer(999999);
- var from = string.IsNullOrWhiteSpace(parameters["from"]) ? "Server Admin" : parameters["from"];
+ var from = string.IsNullOrWhiteSpace(args.Parameters["from"]) ? "Server Admin" : args.Parameters["from"];
player.SendMessage(string.Format("{0} just killed you!", from));
return RestResponse("Player " + player.Name + " was killed");
}
@@ -644,7 +668,7 @@ namespace TShockAPI
#region RestGroupMethods
- private object GroupList(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object GroupList(RestRequestArgs args)
{
var groups = new ArrayList();
foreach (Group group in TShock.Groups)
@@ -654,9 +678,9 @@ namespace TShockAPI
return new RestObject() { { "groups", groups } };
}
- private object GroupInfo(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object GroupInfo(RestRequestArgs args)
{
- var ret = GroupFind(parameters);
+ var ret = GroupFind(args.Parameters);
if (ret is RestObject)
return ret;
@@ -671,9 +695,9 @@ namespace TShockAPI
};
}
- private object GroupDestroy(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object GroupDestroy(RestRequestArgs args)
{
- var ret = GroupFind(parameters);
+ var ret = GroupFind(args.Parameters);
if (ret is RestObject)
return ret;
@@ -690,14 +714,14 @@ namespace TShockAPI
return RestResponse("Group '" + group.Name + "' deleted successfully");
}
- private object GroupCreate(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object GroupCreate(RestRequestArgs args)
{
- var name = parameters["group"];
+ var name = args.Parameters["group"];
if (string.IsNullOrWhiteSpace(name))
return RestMissingParam("group");
try
{
- TShock.Groups.AddGroup(name, parameters["parent"], parameters["permissions"], parameters["chatcolor"], true);
+ TShock.Groups.AddGroup(name, args.Parameters["parent"], args.Parameters["permissions"], args.Parameters["chatcolor"], true);
}
catch (Exception e)
{
@@ -707,16 +731,16 @@ namespace TShockAPI
return RestResponse("Group '" + name + "' created successfully");
}
- private object GroupUpdate(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object GroupUpdate(RestRequestArgs args)
{
- var ret = GroupFind(parameters);
+ var ret = GroupFind(args.Parameters);
if (ret is RestObject)
return ret;
Group group = (Group)ret;
- var parent = (null == parameters["parent"]) ? group.ParentName : parameters["parent"];
- var chatcolor = (null == parameters["chatcolor"]) ? string.Format("{0}.{1}.{2}", group.R, group.G, group.B) : parameters["chatcolor"];
- var permissions = (null == parameters["permissions"]) ? group.Permissions : parameters["permissions"];
+ var parent = (null == args.Parameters["parent"]) ? group.ParentName : args.Parameters["parent"];
+ var chatcolor = (null == args.Parameters["chatcolor"]) ? string.Format("{0}.{1}.{2}", group.R, group.G, group.B) : args.Parameters["chatcolor"];
+ var permissions = (null == args.Parameters["permissions"]) ? group.Permissions : args.Parameters["permissions"];
try
{
TShock.Groups.UpdateGroup(group.Name, parent, permissions, chatcolor, group.Suffix, group.Prefix);
diff --git a/TShockAPI/Rest/RestObject.cs b/TShockAPI/Rest/RestObject.cs
index 4edfae9c..65503bec 100644
--- a/TShockAPI/Rest/RestObject.cs
+++ b/TShockAPI/Rest/RestObject.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Rest/RestPermissions.cs b/TShockAPI/Rest/RestPermissions.cs
index 396a2947..5b8c765d 100644
--- a/TShockAPI/Rest/RestPermissions.cs
+++ b/TShockAPI/Rest/RestPermissions.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Rest/RestVerbs.cs b/TShockAPI/Rest/RestVerbs.cs
index c63642d4..ab8c1500 100644
--- a/TShockAPI/Rest/RestVerbs.cs
+++ b/TShockAPI/Rest/RestVerbs.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/Rest/SecureRest.cs b/TShockAPI/Rest/SecureRest.cs
index 7e8496b4..ee9eac2f 100644
--- a/TShockAPI/Rest/SecureRest.cs
+++ b/TShockAPI/Rest/SecureRest.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -84,9 +84,9 @@ namespace Rests
}
}
- private object DestroyToken(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object DestroyToken(RestRequestArgs args)
{
- var token = verbs["token"];
+ var token = args.Verbs["token"];
try
{
Tokens.Remove(token);
@@ -100,7 +100,7 @@ namespace Rests
{ Response = "Requested token was successfully destroyed." };
}
- private object DestroyAllTokens(RestVerbs verbs, IParameterCollection parameters, SecureRest.TokenData tokenData)
+ private object DestroyAllTokens(RestRequestArgs args)
{
Tokens.Clear();
@@ -108,18 +108,18 @@ namespace Rests
{ Response = "All tokens were successfully destroyed." };
}
- private object NewTokenV2(RestVerbs verbs, IParameterCollection parameters)
+ private object NewTokenV2(RestRequestArgs args)
{
- var user = parameters["username"];
- var pass = verbs["password"];
+ var user = args.Parameters["username"];
+ var pass = args.Verbs["password"];
return this.NewTokenInternal(user, pass);
}
- private object NewToken(RestVerbs verbs, IParameterCollection parameters)
+ private object NewToken(RestRequestArgs args)
{
- var user = verbs["username"];
- var pass = verbs["password"];
+ var user = args.Verbs["username"];
+ var pass = args.Verbs["password"];
RestObject response = this.NewTokenInternal(user, pass);
response["deprecated"] = "This endpoint is depracted and will be removed in the future.";
@@ -157,10 +157,10 @@ namespace Rests
return response;
}
- protected override object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms)
+ protected override object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms, IRequest request)
{
if (!cmd.RequiresToken)
- return base.ExecuteCommand(cmd, verbs, parms);
+ return base.ExecuteCommand(cmd, verbs, parms, request);
var token = parms["token"];
if (token == null)
@@ -191,7 +191,7 @@ namespace Rests
}
}
- object result = secureCmd.Execute(verbs, parms, tokenData);
+ object result = secureCmd.Execute(verbs, parms, tokenData, request);
if (cmd.DoLog && TShock.Config.LogRest)
TShock.Utils.SendLogs(string.Format(
"\"{0}\" requested REST endpoint: {1}", tokenData.Username, this.BuildRequestUri(cmd, verbs, parms, false)),
diff --git a/TShockAPI/SaveManager.cs b/TShockAPI/SaveManager.cs
index 3b001a0f..0557183d 100644
--- a/TShockAPI/SaveManager.cs
+++ b/TShockAPI/SaveManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -125,12 +125,12 @@ namespace TShockAPI
if (task.direct)
{
OnSaveWorld(new WorldSaveEventArgs());
- WorldGen.realsaveWorld(task.resetTime);
+ WorldFile.RealSaveWorld(task.resetTime);
}
else
- WorldGen.saveWorld(task.resetTime);
- TShock.Utils.Broadcast("World saved.", Color.Yellow);
- Log.Info(string.Format("World saved at ({0})", Main.worldPathName));
+ WorldFile.saveWorld(task.resetTime);
+ TShock.Utils.Broadcast("World saved.", Color.Yellow);
+ Log.Info(string.Format("World saved at ({0})", Main.worldPathName));
}
catch (Exception e)
{
diff --git a/TShockAPI/ServerSideCharacters/ServerSideConfig.cs b/TShockAPI/ServerSideCharacters/ServerSideConfig.cs
new file mode 100644
index 00000000..ea4cc931
--- /dev/null
+++ b/TShockAPI/ServerSideCharacters/ServerSideConfig.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+/*
+TShock, a server mod for Terraria
+Copyright (C) 2011-2015 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 .
+*/
+
+using System.IO;
+using Newtonsoft.Json;
+
+namespace TShockAPI.ServerSideCharacters
+{
+ public class ServerSideConfig
+ {
+ [Description("Enable server side characters, This stops the client from saving character data! EXPERIMENTAL!!!!!")]
+ public bool Enabled;
+
+ [Description("How often SSC should save, in minutes.")]
+ public int ServerSideCharacterSave = 5;
+
+ [Description("Time, in milliseconds, to disallow discarding items after logging in when ServerSideInventory is ON.")]
+ public int LogonDiscardThreshold = 250;
+
+ [Description("The starting default health for new SSC.")]
+ public int StartingHealth = 100;
+
+ [Description("The starting default mana for new SSC.")]
+ public int StartingMana = 20;
+
+ [Description("The starting default inventory for new SSC.")]
+ public List StartingInventory = new List();
+
+ public static ServerSideConfig Read(string path)
+ {
+ using (var reader = new StreamReader(path))
+ {
+ string txt = reader.ReadToEnd();
+ var config = JsonConvert.DeserializeObject(txt);
+ return config;
+ }
+ }
+
+ public void Write(string path)
+ {
+ using (var writer = new StreamWriter(path))
+ {
+ writer.Write(JsonConvert.SerializeObject(this, Formatting.Indented));
+ }
+ }
+ }
+}
diff --git a/TShockAPI/StatTracker.cs b/TShockAPI/StatTracker.cs
index a3381bf7..d8f422c5 100644
--- a/TShockAPI/StatTracker.cs
+++ b/TShockAPI/StatTracker.cs
@@ -6,6 +6,7 @@ using System.Net;
using System.Threading;
using System.IO;
using System.Web;
+using TerrariaApi.Server;
namespace TShockAPI
{
@@ -27,21 +28,6 @@ namespace TShockAPI
}
}
- private HttpWebResponse GetResponseNoException(HttpWebRequest req)
- {
- try
- {
- return (HttpWebResponse)req.GetResponse();
- }
- catch (WebException we)
- {
- var resp = we.Response as HttpWebResponse;
- if (resp == null)
- throw;
- return resp;
- }
- }
-
private void SendUpdate(object info)
{
Thread.Sleep(1000*60*15);
@@ -54,7 +40,7 @@ namespace TShockAPI
systemCPUClock = 0,
version = TShock.VersionNum.ToString(),
terrariaVersion = Terraria.Main.versionNumber2,
- mono = Terraria.Main.runningMono
+ mono = ServerApi.RunningMono
};
var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(data);
@@ -64,7 +50,7 @@ namespace TShockAPI
client.Timeout = 5000;
try
{
- using (var resp = GetResponseNoException(client))
+ using (var resp = TShock.Utils.GetResponseNoException(client))
{
if (resp.StatusCode != HttpStatusCode.OK)
{
diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs
index 67bee342..3c711431 100755
--- a/TShockAPI/TSPlayer.cs
+++ b/TShockAPI/TSPlayer.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -40,11 +40,6 @@ namespace TShockAPI
///
public static readonly TSPlayer All = new TSPlayer("All");
- ///
- /// Gets whether the player is using Raptor.
- ///
- public bool IsRaptor { get; internal set; }
-
///
/// The amount of tiles that the player has killed in the last second.
///
@@ -74,17 +69,20 @@ namespace TShockAPI
/// A timer to keep track of whether or not the player has recently thrown an explosive
///
public int RecentFuse = 0;
-
+
+ ///
+ /// Whether to ignore packets that are SSC-relevant.
+ ///
+ public bool IgnoreSSCPackets { get; set; }
+
///
/// A system to delay Remembered Position Teleports a few seconds
///
-
public int RPPending = 0;
public int sX = -1;
public int sY = -1;
-
///
/// A queue of tiles destroyed by the player for reverting.
///
@@ -95,10 +93,6 @@ namespace TShockAPI
///
public Dictionary TilesCreated { get; protected set; }
- public int FirstMaxHP { get; set; }
-
- public int FirstMaxMP { get; set; }
-
///
/// The player's group.
///
@@ -219,10 +213,10 @@ namespace TShockAPI
public bool RequestedSection;
- ///
- /// The last time the player died.
- ///
- public DateTime LastDeath { get; set; }
+ ///
+ /// The player's respawn timer.
+ ///
+ public int RespawnTimer;
///
/// Whether the player is dead or not.
@@ -369,13 +363,22 @@ namespace TShockAPI
}
}
+ public IEnumerable- Accessories
+ {
+ get
+ {
+ for (int i = 3; i < 8; i++)
+ yield return TPlayer.armor[i];
+ }
+ }
+
///
/// Saves the player's inventory to SSI
///
/// bool - True/false if it saved successfully
public bool SaveServerCharacter()
{
- if (!TShock.Config.ServerSideCharacter)
+ if (!Main.ServerSideCharacter)
{
return false;
}
@@ -398,7 +401,7 @@ namespace TShockAPI
/// bool - True/false if it saved successfully
public bool SendServerCharacter()
{
- if (!TShock.Config.ServerSideCharacter)
+ if (!Main.ServerSideCharacter)
{
return false;
}
@@ -520,65 +523,68 @@ namespace TShockAPI
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 = tilex,
- SpawnY = tiley,
- 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 = !fakeid ? Main.worldID : -1,
- 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) |
- (Main.pumpkinMoon ? BossFlags2.Pumpkin : BossFlags2.None),
- Rain = Main.maxRaining,
- WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
- };
+ {
+ Time = (int)Main.time,
+ DayTime = Main.dayTime,
+ MoonPhase = (byte)Main.moonPhase,
+ BloodMoon = Main.bloodMoon,
+ Eclipse = Main.eclipse,
+ MaxTilesX = (short)Main.maxTilesX,
+ MaxTilesY = (short)Main.maxTilesY,
+ SpawnX = (short)Main.spawnTileX,
+ SpawnY = (short)Main.spawnTileY,
+ WorldSurface = (short)Main.worldSurface,
+ RockLayer = (short)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) |
+ (NPC.downedPlantBoss ? BossFlags.DownedPlantBoss : 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) |
+ (Main.pumpkinMoon ? BossFlags2.PumpkinMoon : BossFlags2.None) |
+ (Main.snowMoon ? BossFlags2.SnowMoon : BossFlags2.None),
+ Rain = Main.maxRaining,
+ WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
+ };
msg.PackFull(ms);
SendRawData(ms.ToArray());
}
@@ -609,7 +615,7 @@ namespace TShockAPI
return true;
}
- public void Heal(int health = 500)
+ public void Heal(int health = 600)
{
NetMessage.SendData((int)PacketTypes.PlayerHealOther, -1, -1, "", this.TPlayer.whoAmi, health);
}
@@ -634,8 +640,8 @@ namespace TShockAPI
var msg = new SpawnMsg
{
PlayerIndex = (byte) Index,
- TileX = tilex,
- TileY = tiley
+ TileX = (short)tilex,
+ TileY = (short)tiley
};
msg.PackFull(ms);
SendRawData(ms.ToArray());
@@ -809,6 +815,7 @@ namespace TShockAPI
private DateTime LastDisableNotification = DateTime.UtcNow;
public int ActiveChest = -1;
+ public Item ItemInHand = new Item();
public virtual void Disable(string reason = "", bool displayConsole = true)
{
@@ -884,183 +891,11 @@ namespace TShockAPI
NetMessage.SendData((int) msgType, Index, -1, text, ply, number2, number3, number4, number5);
}
- public virtual bool SendRawData(byte[] data)
+ public virtual void SendRawData(byte[] data)
{
if (!RealPlayer || !ConnectionAlive)
- return false;
-
- return TShock.SendBytes(Netplay.serverSock[Index], data);
- }
-
- ///
- /// Sends Raptor permissions to the player.
- ///
- public void SendRaptorPermissions()
- {
- if (!IsRaptor)
return;
-
- lock (NetMessage.buffer[Index].writeBuffer)
- {
- int length = 0;
-
- using (var ms = new MemoryStream(NetMessage.buffer[Index].writeBuffer, true))
- {
- using (var writer = new BinaryWriter(ms))
- {
- writer.BaseStream.Position = 4;
-
- writer.Write((byte)PacketTypes.Placeholder);
- writer.Write((byte)RaptorPacketTypes.Permissions);
-
- writer.Write(String.Join(",", Group.TotalPermissions.ToArray()));
-
- length = (int)writer.BaseStream.Position;
- writer.BaseStream.Position = 0;
- writer.Write(length - 4);
- }
- }
-
- TShock.PacketBuffer.SendBytes(Netplay.serverSock[Index], NetMessage.buffer[Index].writeBuffer, 0, length);
- }
- }
- ///
- /// Sends a region to the player.
- /// The region.
- ///
- public void SendRaptorRegion(Region region)
- {
- if (!IsRaptor)
- return;
-
- lock (NetMessage.buffer[Index].writeBuffer)
- {
- int length = 0;
-
- using (var ms = new MemoryStream(NetMessage.buffer[Index].writeBuffer, true))
- {
- using (var writer = new BinaryWriter(ms))
- {
- writer.BaseStream.Position = 4;
-
- writer.Write((byte)PacketTypes.Placeholder);
- writer.Write((byte)RaptorPacketTypes.Region);
-
- writer.Write(region.Area.X);
- writer.Write(region.Area.Y);
- writer.Write(region.Area.Width);
- writer.Write(region.Area.Height);
- writer.Write(region.Name);
-
- length = (int)writer.BaseStream.Position;
- writer.BaseStream.Position = 0;
- writer.Write(length - 4);
- }
- }
-
- TShock.PacketBuffer.SendBytes(Netplay.serverSock[Index], NetMessage.buffer[Index].writeBuffer, 0, length);
- }
- }
- ///
- /// Sends a region deletion to the player.
- /// The region name.
- ///
- public void SendRaptorRegionDeletion(string regionName)
- {
- if (!IsRaptor)
- return;
-
- lock (NetMessage.buffer[Index].writeBuffer)
- {
- int length = 0;
-
- using (var ms = new MemoryStream(NetMessage.buffer[Index].writeBuffer, true))
- {
- using (var writer = new BinaryWriter(ms))
- {
- writer.BaseStream.Position = 4;
-
- writer.Write((byte)PacketTypes.Placeholder);
- writer.Write((byte)RaptorPacketTypes.RegionDelete);
-
- writer.Write(regionName);
-
- length = (int)writer.BaseStream.Position;
- writer.BaseStream.Position = 0;
- writer.Write(length - 4);
- }
- }
-
- TShock.PacketBuffer.SendBytes(Netplay.serverSock[Index], NetMessage.buffer[Index].writeBuffer, 0, length);
- }
- }
- ///
- /// Sends a warp to the player.
- /// The warp.
- ///
- public void SendRaptorWarp(Warp warp)
- {
- if (!IsRaptor)
- return;
-
- lock (NetMessage.buffer[Index].writeBuffer)
- {
- int length = 0;
-
- using (var ms = new MemoryStream(NetMessage.buffer[Index].writeBuffer, true))
- {
- using (var writer = new BinaryWriter(ms))
- {
- writer.BaseStream.Position = 4;
-
- writer.Write((byte)PacketTypes.Placeholder);
- writer.Write((byte)RaptorPacketTypes.Warp);
-
- writer.Write(warp.Position.X);
- writer.Write(warp.Position.Y);
- writer.Write(warp.Name);
-
- length = (int)writer.BaseStream.Position;
- writer.BaseStream.Position = 0;
- writer.Write(length - 4);
- }
- }
-
- TShock.PacketBuffer.SendBytes(Netplay.serverSock[Index], NetMessage.buffer[Index].writeBuffer, 0, length);
- }
- }
- ///
- /// Sends a warp deletion to the player.
- /// The warp name.
- ///
- public void SendRaptorWarpDeletion(string warpName)
- {
- if (!IsRaptor)
- return;
-
- lock (NetMessage.buffer[Index].writeBuffer)
- {
- int length = 0;
-
- using (var ms = new MemoryStream(NetMessage.buffer[Index].writeBuffer, true))
- {
- using (var writer = new BinaryWriter(ms))
- {
- writer.BaseStream.Position = 4;
-
- writer.Write((byte)PacketTypes.Placeholder);
- writer.Write((byte)RaptorPacketTypes.WarpDelete);
-
- writer.Write(warpName);
-
- length = (int)writer.BaseStream.Position;
- writer.BaseStream.Position = 0;
- writer.Write(length - 4);
- }
- }
-
- TShock.PacketBuffer.SendBytes(Netplay.serverSock[Index], NetMessage.buffer[Index].writeBuffer, 0, length);
- }
+ NetMessage.SendBytes(Netplay.serverSock[Index], data, 0, data.Length, Netplay.serverSock[Index].ServerWriteCallBack, Netplay.serverSock[Index].networkStream);
}
///
@@ -1184,42 +1019,70 @@ namespace TShockAPI
//RconHandler.Response += msg + "\n";
}
- public void SetFullMoon(bool fullmoon)
+ public void SetFullMoon()
{
+ Main.dayTime = false;
Main.moonPhase = 0;
- SetTime(false, 0);
+ Main.time = 0.0;
+ TSPlayer.All.SendData(PacketTypes.WorldInfo);
}
public void SetBloodMoon(bool bloodMoon)
{
- Main.bloodMoon = bloodMoon;
- SetTime(false, 0);
+ if (bloodMoon)
+ {
+ Main.dayTime = false;
+ Main.bloodMoon = true;
+ Main.time = 0.0;
+ }
+ else
+ Main.bloodMoon = false;
+ TSPlayer.All.SendData(PacketTypes.WorldInfo);
}
- public void SetSnowMoon(bool snowMoon)
+ public void SetFrostMoon(bool snowMoon)
{
- Main.snowMoon = snowMoon;
- SetTime(false, 0);
+ if (snowMoon)
+ {
+ Main.dayTime = false;
+ Main.snowMoon = true;
+ Main.time = 0.0;
+ }
+ else
+ Main.snowMoon = false;
+ TSPlayer.All.SendData(PacketTypes.WorldInfo);
}
public void SetPumpkinMoon(bool pumpkinMoon)
{
- Main.pumpkinMoon = pumpkinMoon;
- SetTime(false, 0);
+ if (pumpkinMoon)
+ {
+ Main.dayTime = false;
+ Main.pumpkinMoon = true;
+ Main.time = 0.0;
+ }
+ else
+ Main.pumpkinMoon = false;
+ TSPlayer.All.SendData(PacketTypes.WorldInfo);
}
- public void SetEclipse(bool Eclipse)
+ public void SetEclipse(bool eclipse)
{
- Main.eclipse = Eclipse;
- SetTime(true, 150);
+ if (eclipse)
+ {
+ Main.dayTime = Main.eclipse = true;
+ Main.time = 0.0;
+ }
+ else
+ Main.eclipse = false;
+ TSPlayer.All.SendData(PacketTypes.WorldInfo);
}
public void SetTime(bool dayTime, double time)
{
Main.dayTime = dayTime;
Main.time = time;
- NetMessage.SendData((int) PacketTypes.TimeSet, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY);
- NetMessage.syncPlayers();
+ TSPlayer.All.SendData(PacketTypes.TimeSet, "", 0, 0, Main.sunModY, Main.moonModY);
}
public void SpawnNPC(int type, string name, int amount, int startTileX, int startTileY, int tileXRange = 100,
@@ -1265,14 +1128,24 @@ namespace TShockAPI
public class PlayerData
{
public NetItem[] inventory = new NetItem[NetItem.maxNetInventory];
- public int health = 100;
- public int maxHealth = 100;
- public int mana = 20;
- public int maxMana = 20;
+ public int health = TShock.ServerSideCharacterConfig.StartingHealth;
+ public int maxHealth = TShock.ServerSideCharacterConfig.StartingHealth;
+ public int mana = TShock.ServerSideCharacterConfig.StartingMana;
+ public int maxMana = TShock.ServerSideCharacterConfig.StartingMana;
public bool exists;
public int spawnX= -1;
public int spawnY= -1;
-
+ public int? hair;
+ public byte hairDye;
+ public Color? hairColor;
+ public Color? pantsColor;
+ public Color? shirtColor;
+ public Color? underShirtColor;
+ public Color? shoeColor;
+ public Color? skinColor;
+ public Color? eyeColor;
+ public BitsByte? hideVisuals;
+ public int questsCompleted;
public PlayerData(TSPlayer player)
{
@@ -1292,7 +1165,12 @@ namespace TShockAPI
this.inventory[2].stack = 1;
if (player.TPlayer.inventory[2] != null && player.TPlayer.inventory[2].netID == -16)
this.inventory[2].prefix = player.TPlayer.inventory[2].prefix;
-
+
+ for (int i = 0; i < TShock.ServerSideCharacterConfig.StartingInventory.Count; i++)
+ {
+ var item = TShock.ServerSideCharacterConfig.StartingInventory[i];
+ StoreSlot(i, item.netID, item.prefix, item.stack);
+ }
}
public void StoreSlot(int slot, int netID, int prefix, int stack)
@@ -1331,6 +1209,18 @@ namespace TShockAPI
this.spawnX = player.TPlayer.SpawnX;
this.spawnY = player.TPlayer.SpawnY;
}
+ this.hair = player.TPlayer.hair;
+ this.hairDye = player.TPlayer.hairDye;
+ this.hairColor = player.TPlayer.hairColor;
+ this.pantsColor = player.TPlayer.pantsColor;
+ this.shirtColor = player.TPlayer.shirtColor;
+ this.underShirtColor = player.TPlayer.underShirtColor;
+ this.shoeColor = player.TPlayer.shoeColor;
+ this.hideVisuals = player.TPlayer.hideVisual;
+ this.skinColor = player.TPlayer.skinColor;
+ this.eyeColor = player.TPlayer.eyeColor;
+ this.questsCompleted = player.TPlayer.anglerQuestsFinished;
+
Item[] inventory = player.TPlayer.inventory;
Item[] armor = player.TPlayer.armor;
Item[] dye = player.TPlayer.dye;
@@ -1409,6 +1299,9 @@ namespace TShockAPI
public void RestoreCharacter(TSPlayer player)
{
+ // Start ignoring SSC-related packets! This is critical so that we don't send or receive dirty data!
+ player.IgnoreSSCPackets = true;
+
player.TPlayer.statLife = this.health;
player.TPlayer.statLifeMax = this.maxHealth;
player.TPlayer.statMana = this.maxMana;
@@ -1417,6 +1310,30 @@ namespace TShockAPI
player.TPlayer.SpawnY = this.spawnY;
player.sX = this.spawnX;
player.sY = this.spawnY;
+ player.TPlayer.hairDye = this.hairDye;
+ player.TPlayer.anglerQuestsFinished = this.questsCompleted;
+
+ if (this.hair != null)
+ player.TPlayer.hair = this.hair.Value;
+ if (this.hairColor != null)
+ player.TPlayer.hairColor = this.hairColor.Value;
+ if (this.pantsColor != null)
+ player.TPlayer.pantsColor = this.pantsColor.Value;
+ if (this.shirtColor != null)
+ player.TPlayer.shirtColor = this.shirtColor.Value;
+ if (this.underShirtColor != null)
+ player.TPlayer.underShirtColor = this.underShirtColor.Value;
+ if (this.shoeColor != null)
+ player.TPlayer.shoeColor = this.shoeColor.Value;
+ if (this.skinColor != null)
+ player.TPlayer.skinColor = this.skinColor.Value;
+ if (this.eyeColor != null)
+ player.TPlayer.eyeColor = this.eyeColor.Value;
+
+ if (this.hideVisuals != null)
+ player.TPlayer.hideVisual = this.hideVisuals.Value;
+ else
+ player.TPlayer.hideVisual.ClearAll();
for (int i = 0; i < NetItem.maxNetInventory; i++)
{
@@ -1490,9 +1407,19 @@ namespace TShockAPI
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0);
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0);
- NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[0].name, player.Index, 70f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0);
- NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[1].name, player.Index, 71f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0);
- NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[2].name, player.Index, 72f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[11].name, player.Index, 70f, (float)Main.player[player.Index].armor[11].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[12].name, player.Index, 71f, (float)Main.player[player.Index].armor[12].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[13].name, player.Index, 72f, (float)Main.player[player.Index].armor[13].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[14].name, player.Index, 73f, (float)Main.player[player.Index].armor[14].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[15].name, player.Index, 74f, (float)Main.player[player.Index].armor[15].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[0].name, player.Index, 75f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[1].name, player.Index, 76f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[2].name, player.Index, 77f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[3].name, player.Index, 78f, (float)Main.player[player.Index].dye[3].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[4].name, player.Index, 79f, (float)Main.player[player.Index].dye[4].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[5].name, player.Index, 80f, (float)Main.player[player.Index].dye[5].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[6].name, player.Index, 81f, (float)Main.player[player.Index].dye[6].prefix, 0f, 0);
+ NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[7].name, player.Index, 82f, (float)Main.player[player.Index].dye[7].prefix, 0f, 0);
NetMessage.SendData(4, -1, -1, player.Name, player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(42, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(16, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
@@ -1501,61 +1428,67 @@ namespace TShockAPI
{
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].inventory[k].name, player.Index, (float)k, (float)Main.player[player.Index].inventory[k].prefix, 0f, 0);
}
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[0].name, player.Index, 59f, (float)Main.player[player.Index].armor[0].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[1].name, player.Index, 60f, (float)Main.player[player.Index].armor[1].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[2].name, player.Index, 61f, (float)Main.player[player.Index].armor[2].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[3].name, player.Index, 62f, (float)Main.player[player.Index].armor[3].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[4].name, player.Index, 63f, (float)Main.player[player.Index].armor[4].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[5].name, player.Index, 64f, (float)Main.player[player.Index].armor[5].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[6].name, player.Index, 65f, (float)Main.player[player.Index].armor[6].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[7].name, player.Index, 66f, (float)Main.player[player.Index].armor[7].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[0].name, player.Index, 70f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[1].name, player.Index, 71f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0);
- NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[2].name, player.Index, 72f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[0].name, player.Index, 59f, (float)Main.player[player.Index].armor[0].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[1].name, player.Index, 60f, (float)Main.player[player.Index].armor[1].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[2].name, player.Index, 61f, (float)Main.player[player.Index].armor[2].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[3].name, player.Index, 62f, (float)Main.player[player.Index].armor[3].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[4].name, player.Index, 63f, (float)Main.player[player.Index].armor[4].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[5].name, player.Index, 64f, (float)Main.player[player.Index].armor[5].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[6].name, player.Index, 65f, (float)Main.player[player.Index].armor[6].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[7].name, player.Index, 66f, (float)Main.player[player.Index].armor[7].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[11].name, player.Index, 70f, (float)Main.player[player.Index].armor[11].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[12].name, player.Index, 71f, (float)Main.player[player.Index].armor[12].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[13].name, player.Index, 72f, (float)Main.player[player.Index].armor[13].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[14].name, player.Index, 73f, (float)Main.player[player.Index].armor[14].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[15].name, player.Index, 74f, (float)Main.player[player.Index].armor[15].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[0].name, player.Index, 75f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[1].name, player.Index, 76f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[2].name, player.Index, 77f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[3].name, player.Index, 78f, (float)Main.player[player.Index].dye[3].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[4].name, player.Index, 79f, (float)Main.player[player.Index].dye[4].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[5].name, player.Index, 80f, (float)Main.player[player.Index].dye[5].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[6].name, player.Index, 81f, (float)Main.player[player.Index].dye[6].prefix, 0f, 0);
+ NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[7].name, player.Index, 82f, (float)Main.player[player.Index].dye[7].prefix, 0f, 0);
NetMessage.SendData(4, player.Index, -1, player.Name, player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(42, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(16, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);
- for (int k = 0; k < 10; k++)
+ for (int k = 0; k < 22; k++)
{
player.TPlayer.buffType[k] = 0;
}
NetMessage.SendData(50, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(50, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);
+ NetMessage.SendData(76, -1, -1, "", player.Index);
+
+ NetMessage.SendData(39, player.Index, -1, "", 400);
}
}
public class NetItem
{
- public static readonly int maxNetInventory = 73;
- public static readonly int armorSlots = 11;
- public static readonly int dyeSlots = 3;
+ public static readonly int maxNetInventory = 83;
+ public static readonly int armorSlots = 16;
+ public static readonly int dyeSlots = 8;
public int netID;
public int stack;
public int prefix;
public static string ToString(NetItem[] inventory)
{
- string inventoryString = "";
+ StringBuilder items = new StringBuilder();
for (int i = 0; i < maxNetInventory; i++)
{
- if (i != 0)
- inventoryString += "~";
- inventoryString += inventory[i].netID;
+ items.Append(inventory[i].netID).Append(",");
if (inventory[i].netID != 0)
- {
- inventoryString += "," + inventory[i].stack;
- inventoryString += "," + inventory[i].prefix;
- }
+ items.Append(inventory[i].stack).Append(",").Append(inventory[i].prefix).Append("~");
else
- {
- inventoryString += ",0,0";
- }
+ items.Append("0,0~");
}
- return inventoryString;
+ return items.ToString(0, items.Length - 1);
}
public static NetItem[] Parse(string data)
diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs
index 647693da..04a4551f 100755
--- a/TShockAPI/TShock.cs
+++ b/TShockAPI/TShock.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -38,10 +38,11 @@ using TShockAPI.DB;
using TShockAPI.Net;
using System.Threading;
using System.Threading.Tasks;
+using TShockAPI.ServerSideCharacters;
namespace TShockAPI
{
- [ApiVersion(1, 14)]
+ [ApiVersion(1, 16)]
public class TShock : TerrariaPlugin
{
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
@@ -62,9 +63,12 @@ namespace TShockAPI
public static GroupManager Groups;
public static UserManager Users;
public static ItemManager Itembans;
+ public static ProjectileManagager ProjectileBans;
+ public static TileManager TileBans;
public static RememberedPosManager RememberedPos;
public static CharacterManager CharacterDB;
public static ConfigFile Config { get; set; }
+ public static ServerSideConfig ServerSideCharacterConfig;
public static IDbConnection DB;
public static bool OverridePort;
public static PacketBufferer PacketBuffer;
@@ -72,7 +76,7 @@ namespace TShockAPI
public static SecureRest RestApi;
public static RestManager RestManager;
public static Utils Utils = Utils.Instance;
- public static StatTracker StatTracker = new StatTracker();
+ public static UpdateManager UpdateManager;
///
/// Used for implementing REST Tokens prior to the REST system starting up.
///
@@ -111,6 +115,10 @@ namespace TShockAPI
: base(game)
{
Config = new ConfigFile();
+ ServerSideCharacterConfig = new ServerSideConfig();
+ ServerSideCharacterConfig.StartingInventory.Add(new NetItem { netID = -15, prefix = 0, stack = 1 });
+ ServerSideCharacterConfig.StartingInventory.Add(new NetItem { netID = -13, prefix = 0, stack = 1 });
+ ServerSideCharacterConfig.StartingInventory.Add(new NetItem { netID = -16, prefix = 0, stack = 1 });
Order = 0;
}
@@ -131,7 +139,7 @@ namespace TShockAPI
ConfigFile.ConfigRead += OnConfigRead;
FileTools.SetupConfig();
- Main.ServerSideCharacter = Config.ServerSideCharacter; //FYI, This cannot be disabled once flipped.
+ Main.ServerSideCharacter = ServerSideCharacterConfig.Enabled;
DateTime now = DateTime.Now;
string logFilename;
@@ -223,6 +231,8 @@ namespace TShockAPI
Users = new UserManager(DB);
Groups = new GroupManager(DB);
Itembans = new ItemManager(DB);
+ ProjectileBans = new ProjectileManagager(DB);
+ TileBans = new TileManager(DB);
RememberedPos = new RememberedPosManager(DB);
CharacterDB = new CharacterManager(DB);
RestApi = new SecureRest(Netplay.serverListenIP, Config.RestApiPort);
@@ -249,7 +259,6 @@ namespace TShockAPI
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);
@@ -327,7 +336,6 @@ namespace TShockAPI
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);
@@ -349,24 +357,6 @@ namespace TShockAPI
private void OnPlayerLogin(Hooks.PlayerPostLoginEventArgs args)
{
- if (args.Player.IsRaptor)
- {
- Task.Factory.StartNew(() =>
- {
- args.Player.SendRaptorPermissions();
- if (args.Player.Group.HasPermission(Permissions.manageregion))
- {
- for (int i = 0; i < Regions.Regions.Count; i++)
- args.Player.SendRaptorRegion(Regions.Regions[i]);
- }
- if (args.Player.Group.HasPermission(Permissions.managewarp))
- {
- for (int i = 0; i < Warps.Warps.Count; i++)
- args.Player.SendRaptorWarp(Warps.Warps[i]);
- }
- });
- }
-
User u = Users.GetUserByName(args.Player.UserAccountName);
List KnownIps = new List();
if (!string.IsNullOrWhiteSpace(u.KnownIps))
@@ -393,38 +383,40 @@ namespace TShockAPI
{
if (args.Player.IsLoggedIn)
args.Player.SaveServerCharacter();
+
+ if (args.Player.ItemInHand.type != 0)
+ {
+ args.Player.SendErrorMessage("Attempting to bypass SSC with item in hand.");
+ args.Handled = true;
+ }
}
- 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 NetHooks_NameCollision(NameCollisionEventArgs args)
+ {
+ string ip = TShock.Utils.GetRealIP(Netplay.serverSock[args.Who].tcpClient.Client.RemoteEndPoint.ToString());
+
+ var player = TShock.Players.First(p => p != null && p.Name == args.Name && p.Index != args.Who);
+ if (player != null)
+ {
+ if (player.IP == ip)
+ {
+ Netplay.serverSock[player.Index].kill = true;
+ args.Handled = true;
+ return;
+ }
+ else if (player.IsLoggedIn)
+ {
+ User user = TShock.Users.GetUserByName(player.UserAccountName);
+ var ips = JsonConvert.DeserializeObject>(user.KnownIps);
+ if (ips.Contains(ip))
+ {
+ Netplay.serverSock[player.Index].kill = true;
+ args.Handled = true;
+ return;
+ }
+ }
+ }
+ }
private void OnXmasCheck(ChristmasCheckEventArgs args)
{
@@ -620,7 +612,7 @@ namespace TShockAPI
ComputeMaxStyles();
FixChestStacks();
- StatTracker.Initialize();
+ UpdateManager = new UpdateManager();
}
private void ComputeMaxStyles()
@@ -664,7 +656,6 @@ namespace TShockAPI
private void OnUpdate(EventArgs args)
{
- UpdateManager.UpdateProcedureCheck();
if (Backups.IsBackupTime)
Backups.Backup();
//call these every second, not every update
@@ -674,7 +665,7 @@ namespace TShockAPI
LastCheck = DateTime.UtcNow;
}
- if (TShock.Config.ServerSideCharacter && (DateTime.UtcNow - LastSave).TotalMinutes >= Config.ServerSideCharacterSave)
+ if (Main.ServerSideCharacter && (DateTime.UtcNow - LastSave).TotalMinutes >= ServerSideCharacterConfig.ServerSideCharacterSave)
{
foreach (TSPlayer player in Players)
{
@@ -741,13 +732,13 @@ namespace TShockAPI
if (player.RecentFuse >0)
player.RecentFuse--;
- if ((TShock.Config.ServerSideCharacter) && (player.TPlayer.SpawnX > 0) &&(player.sX != player.TPlayer.SpawnX))
+ if ((Main.ServerSideCharacter) && (player.TPlayer.SpawnX > 0) &&(player.sX != player.TPlayer.SpawnX))
{
player.sX=player.TPlayer.SpawnX;
player.sY=player.TPlayer.SpawnY;
}
- if ((TShock.Config.ServerSideCharacter) && (player.sX > 0) && (player.sY > 0) && (player.TPlayer.SpawnX < 0))
+ if ((Main.ServerSideCharacter) && (player.sX > 0) && (player.sY > 0) && (player.TPlayer.SpawnX < 0))
{
player.TPlayer.SpawnX = player.sX;
player.TPlayer.SpawnY = player.sY;
@@ -794,21 +785,24 @@ namespace TShockAPI
player.PaintThreshold = 0;
}
- if (player.Dead && (DateTime.Now - player.LastDeath).Seconds >= Config.RespawnSeconds && player.Difficulty != 2)
+ if (player.RespawnTimer > 0 && --player.RespawnTimer == 0 && 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 &&
+ if (!player.Group.HasPermission(Permissions.ignorestackhackdetection) && (item.stack > item.maxStack || item.stack < 0) &&
item.type != 0)
{
check = "Remove item " + item.name + " (" + item.stack + ") exceeds max stack of " + item.maxStack;
+ player.SendErrorMessage(check);
+ break;
}
}
player.IgnoreActionsForCheating = check;
check = "none";
+ //todo: pretty sure we check every place a players inventory can change, so do we really need to do this?
foreach (Item item in player.TPlayer.armor)
{
if (Itembans.ItemIsBanned(item.name, player))
@@ -816,6 +810,9 @@ namespace TShockAPI
player.SetBuff(30, 120); //Bleeding
player.SetBuff(36, 120); //Broken Armor
check = "Remove armor/accessory " + item.name;
+
+ player.SendErrorMessage(string.Format("You are wearing banned equipment. {0}", check));
+ break;
}
}
player.IgnoreActionsForDisabledArmor = check;
@@ -845,8 +842,9 @@ namespace TShockAPI
if (args.Handled)
return;
- if (!Config.AllowCrimsonCreep && (args.Type == 0 || args.Type == 199 || args.Type == 203 || args.Type == 234))
- {
+ if (!Config.AllowCrimsonCreep && (args.Type == 0 || args.Type == 199 || args.Type == 200 || args.Type == 203
+ || args.Type == 234))
+ {
args.Handled = true;
return;
}
@@ -858,7 +856,8 @@ namespace TShockAPI
return;
}
- if (!Config.AllowHallowCreep && (args.Type == 109 || args.Type == 117 || args.Type == 116))
+ if (!Config.AllowHallowCreep && (args.Type == 109 || args.Type == 117 || args.Type == 116 || args.Type == 115
+ || args.Type == 164))
{
args.Handled = true;
}
@@ -973,12 +972,16 @@ namespace TShockAPI
player.Disconnect(String.Format("You are banned for {0} hour{1} and {2} minute{3}: {4}",
ts.Hours, ts.Hours == 1 ? "" : "s", ts.Minutes, ts.Minutes == 1 ? "" : "s", ban.Reason));
}
+ else if (ts.Minutes > 0)
+ {
+ player.Disconnect(String.Format("You are banned for {0} minute{1} and {2} second{3}: {4}",
+ ts.Minutes, ts.Minutes == 1 ? "" : "s", ts.Seconds, ts.Seconds == 1 ? "" : "s", ban.Reason));
+ }
else
{
- player.Disconnect(String.Format("You are banned for {0} minute{1}: {2}",
- ts.Minutes, ts.Minutes == 1 ? "" : "s", ban.Reason));
+ player.Disconnect(String.Format("You are banned for {0} second{1}: {2}",
+ ts.Seconds, ts.Seconds == 1 ? "" : "s", ban.Reason));
}
-
}
args.Handled = true;
}
@@ -996,7 +999,7 @@ namespace TShockAPI
Utils.Broadcast(tsplr.Name + " has 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))
+ if (tsplr.IsLoggedIn && !tsplr.IgnoreActionsForClearingTrashCan && Main.ServerSideCharacter && (!tsplr.Dead || tsplr.TPlayer.difficulty != 2))
{
tsplr.PlayerData.CopyCharacter(tsplr);
CharacterDB.InsertPlayerData(tsplr);
@@ -1034,7 +1037,7 @@ namespace TShockAPI
return;
}*/
- if (args.Text.StartsWith("/") && args.Text.Length > 1)
+ if (args.Text.StartsWith(Config.CommandSpecifier) && !string.IsNullOrWhiteSpace(args.Text.Substring(1)))
{
try
{
@@ -1059,9 +1062,10 @@ namespace TShockAPI
}
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);
+ var text = String.Format(Config.ChatFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix,
+ args.Text);
+ Hooks.PlayerHooks.OnPlayerChat(tsplr, args.Text, ref text);
+ Utils.Broadcast(text, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
args.Handled = true;
}
else
@@ -1071,12 +1075,14 @@ namespace TShockAPI
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);
+ var text = args.Text;
+ Hooks.PlayerHooks.OnPlayerChat(tsplr, args.Text, ref text);
+ NetMessage.SendData((int)PacketTypes.ChatText, -1, args.Who, 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);
+ text);
tsplr.SendMessage(msg, tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
@@ -1141,7 +1147,7 @@ namespace TShockAPI
{
if (e.Handled)
return;
-
+
PacketTypes type = e.MsgID;
Debug.WriteLine("Recv: {0:X}: {2} ({1:XX})", e.Msg.whoAmI, (byte) type, type);
@@ -1160,13 +1166,13 @@ namespace TShockAPI
}
if ((player.State < 10 || player.Dead) && (int) type > 12 && (int) type != 16 && (int) type != 42 && (int) type != 50 &&
- (int) type != 38 && (int) type != 21)
+ (int) type != 38 && (int) type != 21 && (int) type != 22)
{
e.Handled = true;
return;
}
- using (var data = new MemoryStream(e.Msg.readBuffer, e.Index, e.Length))
+ using (var data = new MemoryStream(e.Msg.readBuffer, e.Index, e.Length - 1))
{
// Exceptions are already handled
e.Handled = GetDataHandlers.HandlerGetData(type, player, data);
@@ -1215,7 +1221,7 @@ namespace TShockAPI
if (!player.IsLoggedIn)
{
- if (Config.ServerSideCharacter)
+ if (Main.ServerSideCharacter)
{
player.SendMessage(
player.IgnoreActionsForInventory = "Server side characters is enabled! Please /register or /login to play!",
@@ -1266,14 +1272,6 @@ namespace TShockAPI
e.Object.SetDefaults(0);
}
- private void OnNpcSetDefaults(SetDefaultsEventArgs e)
- {
- if (Itembans.ItemIsBanned(e.Object.name, null))
- {
- e.Object.SetDefaults(0);
- }
- }
-
///
/// Send bytes to client using packetbuffering if available
///
@@ -1351,76 +1349,76 @@ namespace TShockAPI
if (e.remoteClient == -1) return;
var player = Players[e.remoteClient];
if (player == null) return;
- if (Config.UseServerName)
+ using (var ms = new MemoryStream())
{
- using (var ms = new MemoryStream())
+ var msg = new WorldInfoMsg
{
- 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) |
- (Main.pumpkinMoon ? BossFlags2.Pumpkin : BossFlags2.None),
- Rain = Main.maxRaining,
- WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
- };
- msg.PackFull(ms);
- player.SendRawData(ms.ToArray());
- }
- e.Handled = true;
- return;
+ Time = (int)Main.time,
+ DayTime = Main.dayTime,
+ MoonPhase = (byte)Main.moonPhase,
+ BloodMoon = Main.bloodMoon,
+ Eclipse = Main.eclipse,
+ MaxTilesX = (short)Main.maxTilesX,
+ MaxTilesY = (short)Main.maxTilesY,
+ SpawnX = (short)Main.spawnTileX,
+ SpawnY = (short)Main.spawnTileY,
+ WorldSurface = (short)Main.worldSurface,
+ RockLayer = (short)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) |
+ (NPC.downedPlantBoss ? BossFlags.DownedPlantBoss : 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) |
+ (Main.pumpkinMoon ? BossFlags2.PumpkinMoon : BossFlags2.None) |
+ (Main.snowMoon ? BossFlags2.SnowMoon : BossFlags2.None) ,
+ Rain = Main.maxRaining,
+ WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
+ };
+ msg.PackFull(ms);
+ player.SendRawData(ms.ToArray());
}
+ e.Handled = true;
+ return;
}
else if (e.MsgId == PacketTypes.PlayerHp)
{
@@ -1519,11 +1517,6 @@ namespace TShockAPI
Projectile proj = new Projectile();
proj.SetDefaults(type);
- if (Itembans.ItemIsBanned(proj.name, player))
- {
- return true;
- }
-
if (Main.projHostile[type])
{
//player.SendMessage( proj.name, Color.Yellow);
@@ -1542,7 +1535,7 @@ namespace TShockAPI
return false;
}
- public static bool CheckTilePermission(TSPlayer player, int tileX, int tileY, byte tileType, GetDataHandlers.EditAction actionType)
+ public static bool CheckTilePermission(TSPlayer player, int tileX, int tileY, short tileType, GetDataHandlers.EditAction actionType)
{
if (!player.Group.HasPermission(Permissions.canbuild))
{
@@ -1760,7 +1753,7 @@ namespace TShockAPI
public static bool CheckIgnores(TSPlayer player)
{
- return player.IgnoreActionsForInventory != "none" || player.IgnoreActionsForCheating != "none" || player.IgnoreActionsForDisabledArmor != "none" || player.IgnoreActionsForClearingTrashCan || !player.IsLoggedIn && Config.RequireLogin;;
+ return player.IgnoreActionsForInventory != "none" || player.IgnoreActionsForCheating != "none" || player.IgnoreActionsForDisabledArmor != "none" || player.IgnoreActionsForClearingTrashCan || !player.IsLoggedIn && Config.RequireLogin;
}
public void OnConfigRead(ConfigFile file)
diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj
index 3ebc9d93..75ef9782 100644
--- a/TShockAPI/TShockAPI.csproj
+++ b/TShockAPI/TShockAPI.csproj
@@ -72,11 +72,12 @@
+
+
-
@@ -122,6 +123,7 @@
+
diff --git a/TShockAPI/TShockAPI.licenseheader b/TShockAPI/TShockAPI.licenseheader
index 5326a2f0..936b8a9b 100644
--- a/TShockAPI/TShockAPI.licenseheader
+++ b/TShockAPI/TShockAPI.licenseheader
@@ -1,7 +1,7 @@
extensions: .cs
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
diff --git a/TShockAPI/UpdateManager.cs b/TShockAPI/UpdateManager.cs
old mode 100644
new mode 100755
index 27563744..bfb96740
--- a/TShockAPI/UpdateManager.cs
+++ b/TShockAPI/UpdateManager.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -18,32 +18,44 @@ along with this program. If not, see .
using System;
using System.Collections.Generic;
+using System.IO;
using System.Net;
using System.Threading;
using Newtonsoft.Json;
namespace TShockAPI
{
- internal class UpdateManager
+ public class UpdateManager
{
- private static string updateUrl = "http://shankshock.com/tshock-update.json";
- public static DateTime lastcheck = DateTime.MinValue;
+ private string updateUrl = "http://update.tshock.co/latest/";
///
/// Check once every X minutes.
///
- private static readonly int CheckXMinutes = 30;
+ private readonly int CheckXMinutes = 30;
- public static void UpdateProcedureCheck()
+ public UpdateManager()
{
- if ((DateTime.Now - lastcheck).TotalMinutes >= CheckXMinutes)
- {
- ThreadPool.QueueUserWorkItem(CheckUpdate);
- lastcheck = DateTime.Now;
- }
+ ThreadPool.QueueUserWorkItem(CheckForUpdates);
}
- public static void CheckUpdate(object o)
+ private void CheckForUpdates(object state)
+ {
+ try
+ {
+ UpdateCheck(state);
+ }
+ catch (Exception)
+ {
+ //swallow the exception
+ return;
+ }
+
+ Thread.Sleep(CheckXMinutes * 60 * 1000);
+ ThreadPool.QueueUserWorkItem(CheckForUpdates);
+ }
+
+ public void UpdateCheck(object o)
{
var updates = ServerIsOutOfDate();
if (updates != null)
@@ -56,29 +68,39 @@ namespace TShockAPI
/// Checks to see if the server is out of date.
///
///
- private static Dictionary ServerIsOutOfDate()
+ private Dictionary ServerIsOutOfDate()
{
- using (var client = new WebClient())
+ var client = (HttpWebRequest)WebRequest.Create(updateUrl);
+ client.Timeout = 5000;
+ try
{
- client.Headers.Add("user-agent",
- "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705;)");
- try
+ using (var resp = TShock.Utils.GetResponseNoException(client))
{
- string updatejson = client.DownloadString(updateUrl);
- var update = JsonConvert.DeserializeObject>(updatejson);
- var version = new Version(update["version"]);
- if (TShock.VersionNum.CompareTo(version) < 0)
- return update;
+ if (resp.StatusCode != HttpStatusCode.OK)
+ {
+ throw new IOException("Server did not respond with an OK.");
+ }
+
+ using(var reader = new StreamReader(resp.GetResponseStream()))
+ {
+ string updatejson = reader.ReadToEnd();
+ var update = JsonConvert.DeserializeObject>(updatejson);
+ var version = new Version(update["version"]);
+ if (TShock.VersionNum.CompareTo(version) < 0)
+ return update;
+ }
}
- catch (Exception e)
- {
- Log.Error(e.ToString());
- }
- return null;
}
+ catch (Exception e)
+ {
+ Log.ConsoleError("UpdateManager Exception: {0}", e);
+ throw e;
+ }
+
+ return null;
}
- private static void NotifyAdministrators(Dictionary update)
+ private void NotifyAdministrators(Dictionary update)
{
var changes = update["changes"].Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
NotifyAdministrator(TSPlayer.Server, changes);
@@ -91,9 +113,9 @@ namespace TShockAPI
}
}
- private static void NotifyAdministrator(TSPlayer player, string[] changes)
+ private void NotifyAdministrator(TSPlayer player, string[] changes)
{
- player.SendMessage("The server is out of date.", Color.Red);
+ player.SendMessage("The server is out of date. Latest version: ", Color.Red);
for (int j = 0; j < changes.Length; j++)
{
player.SendMessage(changes[j], Color.Red);
diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs
index 5d13d6db..8fc6a0c1 100644
--- a/TShockAPI/Utils.cs
+++ b/TShockAPI/Utils.cs
@@ -1,6 +1,6 @@
/*
TShock, a server mod for Terraria
-Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
+Copyright (C) 2011-2015 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
@@ -442,7 +442,7 @@ namespace TShockAPI
/// name
public string GetBuffName(int id)
{
- return (id > 0 && id < Main.maxBuffs) ? Main.buffName[id] : "null";
+ return (id > 0 && id < Main.maxBuffTypes) ? Main.buffName[id] : "null";
}
///
@@ -452,7 +452,7 @@ namespace TShockAPI
/// description
public string GetBuffDescription(int id)
{
- return (id > 0 && id < Main.maxBuffs) ? Main.buffTip[id] : "null";
+ return (id > 0 && id < Main.maxBuffTypes) ? Main.buffTip[id] : "null";
}
///
@@ -463,13 +463,13 @@ namespace TShockAPI
public List GetBuffByName(string name)
{
string nameLower = name.ToLower();
- for (int i = 1; i < Main.maxBuffs; i++)
+ for (int i = 1; i < Main.maxBuffTypes; i++)
{
if (Main.buffName[i].ToLower() == nameLower)
return new List {i};
}
var found = new List();
- for (int i = 1; i < Main.maxBuffs; i++)
+ for (int i = 1; i < Main.maxBuffTypes; i++)
{
if (Main.buffName[i].ToLower().StartsWith(nameLower))
found.Add(i);
@@ -484,11 +484,7 @@ namespace TShockAPI
/// Prefix name
public string GetPrefixById(int id)
{
- var item = new Item();
- item.SetDefaults(0);
- item.prefix = (byte) id;
- item.AffixName();
- return item.name.Trim();
+ return id < FirstItemPrefix || id > LastItemPrefix ? "" : Lang.prefix[id] ?? "";
}
///
@@ -574,7 +570,7 @@ namespace TShockAPI
/// string reason (default: "Server shutting down!")
public void RestartServer(bool save = true, string reason = "Server shutting down!")
{
- if (TShock.Config.ServerSideCharacter)
+ if (Main.ServerSideCharacter)
foreach (TSPlayer player in TShock.Players)
if (player != null && player.IsLoggedIn && !player.IgnoreActionsForClearingTrashCan)
TShock.CharacterDB.InsertPlayerData(player);
@@ -681,12 +677,11 @@ namespace TShockAPI
string playerName = player.Name;
TShock.Bans.AddBan(ip, playerName, uuid, reason, false, adminUserName);
player.Disconnect(string.Format("Banned: {0}", reason));
- Log.ConsoleInfo(string.Format("Banned {0} for : '{1}'", playerName, reason));
string verb = force ? "force " : "";
if (string.IsNullOrWhiteSpace(adminUserName))
- Broadcast(string.Format("{0} was {1}banned for '{2}'", playerName, verb, reason.ToLower()));
+ TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", playerName, verb, reason);
else
- Broadcast(string.Format("{0} {1}banned {2} for '{3}'", adminUserName, verb, playerName, reason.ToLower()));
+ TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", adminUserName, verb, playerName, reason);
return true;
}
return false;
@@ -893,7 +888,7 @@ namespace TShockAPI
var sb = new StringBuilder(3);
for (int i = 0; i < str.Length; i++)
{
- if (char.IsDigit(str[i]) || (str[i] == '-' || str[i] == '+'))
+ if (Char.IsDigit(str[i]) || (str[i] == '-' || str[i] == '+'))
sb.Append(str[i]);
else
{
@@ -921,6 +916,8 @@ namespace TShockAPI
}
}
}
+ if (sb.Length != 0)
+ return false;
return true;
}
@@ -975,5 +972,62 @@ namespace TShockAPI
yield return new Point(regionArea.Right, regionArea.Top + y);
}
}
+
+ public int? EncodeColor(Color? color)
+ {
+ if (color == null)
+ return null;
+
+ return BitConverter.ToInt32(new[] { color.Value.R, color.Value.G, color.Value.B, color.Value.A }, 0);
+ }
+
+ public Color? DecodeColor(int? encodedColor)
+ {
+ if (encodedColor == null)
+ return null;
+
+ byte[] data = BitConverter.GetBytes(encodedColor.Value);
+ return new Color(data[0], data[1], data[2], data[3]);
+ }
+
+ public byte? EncodeBitsByte(BitsByte? bitsByte)
+ {
+ if (bitsByte == null)
+ return null;
+
+ byte result = 0;
+ for (int i = 0; i < 8; i++)
+ if (bitsByte.Value[i])
+ result |= (byte)(1 << i);
+
+ return result;
+ }
+
+ public BitsByte? DecodeBitsByte(int? encodedBitsByte)
+ {
+ if (encodedBitsByte == null)
+ return null;
+
+ BitsByte result = new BitsByte();
+ for (int i = 0; i < 8; i++)
+ result[i] = (encodedBitsByte & 1 << i) != 0;
+
+ return result;
+ }
+
+ public HttpWebResponse GetResponseNoException(HttpWebRequest req)
+ {
+ try
+ {
+ return (HttpWebResponse)req.GetResponse();
+ }
+ catch (WebException we)
+ {
+ var resp = we.Response as HttpWebResponse;
+ if (resp == null)
+ throw;
+ return resp;
+ }
+ }
}
}
diff --git a/Terraria.vsmdi b/Terraria.vsmdi
deleted file mode 100644
index 5024fe82..00000000
--- a/Terraria.vsmdi
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/TerrariaServerAPI b/TerrariaServerAPI
index 0ddd492a..50a04c45 160000
--- a/TerrariaServerAPI
+++ b/TerrariaServerAPI
@@ -1 +1 @@
-Subproject commit 0ddd492aa03e5c97dddbc95b2e605fa2823804ab
+Subproject commit 50a04c45bfc2d1de2de1a31b215f7bdc546cfdd5
diff --git a/TraceAndTestImpact.testsettings b/TraceAndTestImpact.testsettings
deleted file mode 100644
index de2742ce..00000000
--- a/TraceAndTestImpact.testsettings
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- These are test settings for Trace and Test Impact.
-
-
-
-
-
-
\ No newline at end of file
diff --git a/UnitTests/BanManagerTest.cs b/UnitTests/BanManagerTest.cs
deleted file mode 100644
index b1eabc0c..00000000
--- a/UnitTests/BanManagerTest.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-TShock, a server mod for Terraria
-Copyright (C) 2011-2012 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 .
-*/
-using System;
-using System.Data;
-using System.Text;
-using System.Collections.Generic;
-using System.Linq;
-using Mono.Data.Sqlite;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using TShockAPI;
-using TShockAPI.DB;
-
-namespace UnitTests
-{
- [TestClass]
- public class BanManagerTest
- {
- public static IDbConnection DB;
- private BanManager Bans;
-
- [TestInitialize]
- public void Initialize()
- {
- TShock.Config = new ConfigFile();
- TShock.Config.StorageType = "sqlite";
-
- DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", "tshock.test.sqlite"));
- DB.Open();
-
- Bans = new BanManager(DB);
- }
-
- [TestMethod]
- public void TestBansDBNotNull()
- {
- Assert.IsNotNull(Bans);
- }
-
- [TestMethod]
- public void AddBanTest()
- {
- Assert.IsTrue(Bans.AddBan("127.0.0.1", "BanTest", "BanTest2", "Ban Testing"));
- }
-
- [TestMethod]
- public void FindBanTest()
- {
- Assert.IsNotNull(Bans.GetBanByIp("127.0.0.1"));
- Assert.IsNotNull(Bans.GetBanByName("BanTest"));
- Assert.IsNotNull(Bans.GetBanByUUID("BanTest2"));
- }
- }
-}
diff --git a/UnitTests/BanManagerTest.orderedtest b/UnitTests/BanManagerTest.orderedtest
deleted file mode 100644
index 646da342..00000000
--- a/UnitTests/BanManagerTest.orderedtest
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/UnitTests/GroupManagerTest.cs b/UnitTests/GroupManagerTest.cs
deleted file mode 100644
index 64d23622..00000000
--- a/UnitTests/GroupManagerTest.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-TShock, a server mod for Terraria
-Copyright (C) 2011-2012 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 .
-*/
-using System;
-using System.Data;
-using System.Text;
-using System.Collections.Generic;
-using System.Linq;
-using Mono.Data.Sqlite;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using TShockAPI;
-using TShockAPI.DB;
-
-namespace UnitTests
-{
- [TestClass]
- public class GroupManagerTest
- {
- public static IDbConnection DB;
- private GroupManager Groups;
-
- [TestInitialize]
- public void Initialize()
- {
- TShock.Config = new ConfigFile();
- TShock.Config.StorageType = "sqlite";
-
- DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", "tshock.test.sqlite"));
- DB.Open();
-
- Groups = new GroupManager(DB);
- TShock.Groups = this.Groups;
- }
-
- [TestMethod]
- public void TestGroupsDBNotNull()
- {
- Assert.IsNotNull(Groups);
- }
-
- [TestMethod]
- public void CreateGroup()
- {
- Assert.IsTrue(Groups.AddGroup("test1", "heal") != "");
- Assert.IsTrue(Groups.GroupExists("test1"));
- Assert.IsTrue(TShock.Utils.GetGroup("test1").HasPermission("heal"));
- }
-
- [TestMethod]
- public void DeleteGroup()
- {
- Assert.IsTrue(Groups.AddGroup("test1", "heal") != "");
- Assert.IsTrue(Groups.GroupExists("test1"));
- Assert.IsTrue(Groups.DeleteGroup("test1") != "");
- Assert.IsFalse( Groups.GroupExists( "test1") );
- }
-
- /*[TestMethod]
- public void CreateGroup()
- {
- Assert.IsTrue(Groups.AddGroup("test1", "heal") != "");
- Assert.IsTrue(Groups.GroupExists("test1"));
- Assert.IsTrue(Tools.GetGroup("test1").HasPermission("heal"));
- }*/
- }
-}
diff --git a/UnitTests/GroupManagerTest.orderedtest b/UnitTests/GroupManagerTest.orderedtest
deleted file mode 100644
index b7c5c255..00000000
--- a/UnitTests/GroupManagerTest.orderedtest
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/UnitTests/ItemManagerTest.cs b/UnitTests/ItemManagerTest.cs
deleted file mode 100644
index febd62ab..00000000
--- a/UnitTests/ItemManagerTest.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-TShock, a server mod for Terraria
-Copyright (C) 2011-2012 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 .
-*/
-using System;
-using System.Text;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.IO;
-using System.Data;
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Net;
-using System.Reflection;
-using System.Threading;
-using Mono.Data.Sqlite;
-using TShockAPI.DB;
-using TShockAPI;
-
-namespace UnitTests
-{
-
- ///
- /// Summary description for UnitTest1
- ///
- [TestClass]
- public class ItemManagerTest
- {
- public static IDbConnection DB;
- public static ItemManager manager;
- [TestInitialize]
- public void Initialize()
- {
- TShock.Config = new ConfigFile();
- TShock.Config.StorageType = "sqlite";
-
- DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", "tshock.test.sqlite"));
- DB.Open();
- manager = new ItemManager(DB);
- }
-
- [TestMethod]
- public void SQLiteItemTest_AddBan()
- {
- Assert.IsNotNull(manager);
- Assert.IsFalse( manager.ItemIsBanned("Dirt Block"), "Item isn't banned" );
- manager.AddNewBan("Dirt Block");
- Assert.IsTrue( manager.ItemIsBanned("Dirt Block"), "New item is added");
- Assert.IsFalse( manager.ItemIsBanned("Green Brick"), "Item isn't banned");
- manager.AddNewBan("Green Brick");
- Assert.IsTrue( manager.ItemIsBanned("Green Brick"), "New item is added");
- Assert.AreEqual(2, manager.ItemBans.Count, "Adding both items");
- manager.AddNewBan("Green Brick" );
- Assert.AreEqual(2, manager.ItemBans.Count, "Adding duplicate items");
- }
-
- [TestMethod]
- public void SQLiteItemTest_RemoveBan()
- {
- manager = new ItemManager(DB);
- Assert.IsNotNull(manager);
- Assert.AreEqual(2, manager.ItemBans.Count);
- manager.AddNewBan("Dirt Block");
- Assert.AreEqual(2, manager.ItemBans.Count);
- Assert.AreEqual(true, manager.ItemIsBanned("Dirt Block"));
- manager.RemoveBan("Dirt Block");
- manager.UpdateItemBans();
- Assert.AreEqual(1, manager.ItemBans.Count);
- Assert.AreEqual(false, manager.ItemIsBanned("Dirt Block"));
- manager.RemoveBan("Dirt Block");
- Assert.AreEqual(false, manager.ItemIsBanned("Dirt Block"));
- Assert.AreEqual(true, manager.ItemIsBanned("Green Brick"));
- manager.RemoveBan("Green Brick");
- Assert.AreEqual(false, manager.ItemIsBanned("Green Brick"));
- }
-
- [TestCleanup]
- public void Cleanup()
- {
- DB.Close();
- }
- }
-}
diff --git a/UnitTests/ItemManagerTest.orderedtest b/UnitTests/ItemManagerTest.orderedtest
deleted file mode 100644
index eeb19a9e..00000000
--- a/UnitTests/ItemManagerTest.orderedtest
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/UnitTests/Properties/AssemblyInfo.cs b/UnitTests/Properties/AssemblyInfo.cs
deleted file mode 100644
index 9f57e16a..00000000
--- a/UnitTests/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-TShock, a server mod for Terraria
-Copyright (C) 2011-2012 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 .
-*/
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("UnitTests")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Microsoft")]
-[assembly: AssemblyProduct("UnitTests")]
-[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("edd69981-21b0-42af-bb55-25088efab253")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/UnitTests/RegionManagerTest.cs b/UnitTests/RegionManagerTest.cs
deleted file mode 100644
index 6c4d3ed9..00000000
--- a/UnitTests/RegionManagerTest.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
-TShock, a server mod for Terraria
-Copyright (C) 2011-2012 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 .
-*/
-using System;
-using System.Text;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Data;
-using TShockAPI;
-using Mono.Data.Sqlite;
-using TShockAPI.DB;
-using Region = TShockAPI.DB.Region;
-
-namespace UnitTests
-{
- ///
- /// Summary description for RegionManagerTest
- ///
- [TestClass]
- public class RegionManagerTest
- {
- public static IDbConnection DB;
- public static RegionManager manager;
- [TestInitialize]
- public void Initialize()
- {
- TShock.Config = new ConfigFile();
- TShock.Config.StorageType = "sqlite";
-
- DB = new SqliteConnection(string.Format("uri=file://{0},Version=3", "tshock.test.sqlite"));
- DB.Open();
-
- manager = new RegionManager(DB);
- TShock.Regions = manager;
- manager.ReloadForUnitTest("test");
- }
-
-
- [TestMethod]
- public void AddRegion()
- {
- Region r = new Region( new Rectangle(100,100,100,100), "test", "test", true, "test", 0);
- Assert.IsTrue(manager.AddRegion(r.Area.X, r.Area.Y, r.Area.Width, r.Area.Height, r.Name, r.Owner, r.WorldID));
- Assert.AreEqual(1, manager.Regions.Count);
- Assert.IsNotNull(manager.ZacksGetRegionByName("test"));
-
- Region r2 = new Region(new Rectangle(201, 201, 100, 100), "test2", "test2", true, "test", 0);
- manager.AddRegion(r2.Area.X, r2.Area.Y, r2.Area.Width, r2.Area.Height, r2.Name, r2.Owner, r2.WorldID);
- Assert.AreEqual(2, manager.Regions.Count);
- Assert.IsNotNull(manager.ZacksGetRegionByName("test2"));
- }
-
- [TestMethod]
- public void DeleteRegion()
- {
- Assert.IsTrue(2 == manager.Regions.Count);
- Assert.IsTrue(manager.DeleteRegion("test"));
- Assert.IsTrue(1 == manager.Regions.Count);
- Assert.IsTrue(manager.DeleteRegion("test2"));
- Assert.IsTrue(0 == manager.Regions.Count);
- }
-
- [TestMethod]
- public void InRegion()
- {
- Assert.IsTrue(manager.InArea(100, 100));
- Assert.IsTrue(manager.InArea(150, 150));
- Assert.IsTrue(manager.InArea(200, 200));
- Assert.IsTrue(manager.InArea(201, 201));
- Assert.IsTrue(manager.InArea(251, 251));
- Assert.IsTrue(manager.InArea(301, 301));
- Assert.IsFalse(manager.InArea(311, 311));
- Assert.IsFalse(manager.InArea(99, 99));
- }
-
- [TestMethod]
- public void SetRegionState()
- {
- Assert.IsTrue(manager.ZacksGetRegionByName("test").DisableBuild);
- manager.SetRegionStateTest("test", "test", false);
- Assert.IsTrue(!manager.ZacksGetRegionByName("test").DisableBuild);
- manager.SetRegionStateTest("test", "test", true);
- Assert.IsTrue(manager.ZacksGetRegionByName("test").DisableBuild);
- Assert.IsTrue(manager.ZacksGetRegionByName("test2").DisableBuild);
- manager.SetRegionStateTest("test2", "test", false);
- Assert.IsTrue(!manager.ZacksGetRegionByName("test2").DisableBuild);
- manager.SetRegionStateTest("test2", "test", true);
- Assert.IsTrue(manager.ZacksGetRegionByName("test2").DisableBuild);
- }
-
- [TestMethod]
- public void CanBuild()
- {
- /**
- * For now, this test is useless. Need to implement user groups so we can alter Canbuild permission.
- */
- }
-
- [TestMethod]
- public void AddUser()
- {
- /**
- * For now, this test is useless. Need to implement users so we have names to get ids from.
- */
- }
-
- [TestMethod]
- public void ListID()
- {
- Assert.IsTrue(RegionManager.ListIDs("1,2,3,4,5").Count == 5);
- Assert.IsTrue(RegionManager.ListIDs("").Count == 0);
- }
-
- [TestMethod]
- public void ListRegions()
- {
- //needs a little more work.
- }
-
- [TestCleanup]
- public void Cleanup()
- {
- DB.Close();
- }
- }
-}
diff --git a/UnitTests/RegionManagerTest.orderedtest b/UnitTests/RegionManagerTest.orderedtest
deleted file mode 100644
index 980cc5da..00000000
--- a/UnitTests/RegionManagerTest.orderedtest
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/UnitTests/RestApiTests.webtest b/UnitTests/RestApiTests.webtest
deleted file mode 100644
index 29e27981..00000000
--- a/UnitTests/RestApiTests.webtest
+++ /dev/null
@@ -1,1542 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj
deleted file mode 100644
index 1ca30566..00000000
--- a/UnitTests/UnitTests.csproj
+++ /dev/null
@@ -1,176 +0,0 @@
-
-
-
- Debug
- AnyCPU
-
-
- 2.0
- {F3742F51-D7BF-4754-A68A-CD944D2A21FF}
- Library
- Properties
- UnitTests
- UnitTests
- v4.0
- 512
- {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- false
- publish\
- true
- Disk
- false
- Foreground
- 7
- Days
- false
- false
- true
- 0
- 1.0.0.%2a
- false
- true
- 10.0
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
- $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
- False
- WebTest
-
-
-
-
- 4.0
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
- ..\SqlBins\Mono.Data.Sqlite.dll
-
-
- ..\SqlBins\MySql.Data.dll
-
-
- ..\SqlBins\MySql.Web.dll
-
-
-
- 3.5
-
-
-
-
- False
- .exe
- ..\TerrariaServerBins\TerrariaServer.exe
-
-
-
-
- False
-
-
-
-
-
-
-
-
-
-
-
- {49606449-072B-4CF5-8088-AA49DA586694}
- TShockAPI
-
-
- {F2FEDAFB-58DE-4611-9168-A86112C346C7}
- TShockRestTestPlugin
-
-
-
-
- Always
-
-
- Always
-
-
- Always
-
-
- Always
-
-
-
- Always
-
-
-
-
- False
- Microsoft .NET Framework 4 %28x86 and x64%29
- true
-
-
- False
- .NET Framework 3.5 SP1 Client Profile
- false
-
-
- False
- .NET Framework 3.5 SP1
- false
-
-
- False
- Windows Installer 3.1
- true
-
-
-
-
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
-
-
-
-
-
- xcopy .\..\..\..\SqlBins\sqlite3.dll . /Y
-
-
-
\ No newline at end of file
diff --git a/UnitTests/UnitTests.licenseheader b/UnitTests/UnitTests.licenseheader
deleted file mode 100644
index 12ed0ea9..00000000
--- a/UnitTests/UnitTests.licenseheader
+++ /dev/null
@@ -1,18 +0,0 @@
-extensions: .cs
-/*
-TShock, a server mod for Terraria
-Copyright (C) 2011-2012 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 .
-*/
\ No newline at end of file
diff --git a/tshock_update.json b/tshock_update.json
new file mode 100644
index 00000000..c62d91bf
--- /dev/null
+++ b/tshock_update.json
@@ -0,0 +1,4 @@
+{
+ "version": "4.2.4.0128",
+ "changes": "TShock 4.2.4 for Terraria 1.2.4.1\nhttp://tshock.co/xf/index.php?threads/tshock-4-2-4-for-terraria-1-2-4-1.3398/"
+}